2018.10.8 noip多校联测

T1

avatar

Solution:

根据题意,我们可以得知对于一个点,当只存在一条未知的与它相连的边时,我们是不需要观察它的(流量平衡)

那么很显然,我们最后剩下的是森林,因为我们要最优,所以应该剩下最大生成树森林

不过因为边权可能为负数,所以应该特判最大生成树的边权情况

Code:

#include<cstdio>
#include<ctype.h>
#include<algorithm>
using namespace std;
const int N=3e5+11;
const int M=2e6+11;
long long ans;
int n,m,tot,cnt,num;
int head[N],fa[N],apr[N],pos[N];
struct Edge{int nxt,to,val;}edge[M];
struct EDGE{int x,y,val;}e[M];
inline bool cmp(EDGE a,EDGE b){return a.val>b.val;}
void ins(int x,int y,int z){
    edge[++cnt].nxt=head[x];
    edge[cnt].to=y;head[x]=cnt;
    edge[cnt].val=z;
}
void dfs(int x,int fat){
    apr[x]=1;pos[++num]=x;
    for(int i=head[x];i;i=edge[i].nxt){
        int y=edge[i].to;
        if(y==fat) continue;
        e[++tot]=(EDGE){x,y,edge[i].val};
        if(!apr[y]) dfs(y,x);
    }
}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void work(){
    sort(e+1,e+tot+1,cmp);
    int tim=0;long long re=0;
    for(int i=1;i<=num;i++) fa[pos[i]]=pos[i];
    for(int i=1;i<=tot;i++){
        int x=find(e[i].x),y=find(e[i].y);
        if(x==y) continue;fa[x]=y;
        if(e[i].val>0) re+=e[i].val;
        if(++tim==num-1) return ans-=re,void();
    }
}
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;
}
int main(){
    freopen("traffic.in","r",stdin);
    freopen("traffic.out","w",stdout);
    n=read(),m=read();
    for(int i=1;i<=m;i++){
        int x=read(),y=read(),z=read();
        ins(x,y,z),ins(y,x,z);ans+=z;
    }
    for(int i=1;i<=n;i++)
        if(!apr[i]){
            tot=0,num=0,dfs(i,0);
            work();
        }
    printf("%lld\n",ans);
    return 0;
}

T2

avatar

Solution:

我们先把时间倒过来,再来考虑这道题。

第一个放的点只能是根节点,即1号点,那么我们把当前可以放置的点放到堆里,对每个点记录一个\(f[x]\)

其中\(f[x]=dep[x]+a[x]\),我们把\(f[x]\)最小的拿出来扩展即可,考虑如何证明

假设有一个新的放置序列\(B\),与我们的序列\(A\)在第\(i\)处不同,我们的序列第\(i\)处为\(x\),这个序列为\(y\)

显然有\(f[x]\le f[y]\),且在\(B\)中可以于\(x\)之后找到\(y\),那么我们将\(y\)\(B\)中提前到\(x\)的位置

因为我们将时间倒过来了,所以此时\(B\)序列中\(y\)之后的操作时间都提前了1,这样的序列是肯定不劣于原序列的

我们可以通过有限次操作得到序列\(A\),所以\(A\)即为最优操作序列

Code

#include<cstdio>
#include<queue>
#include<ctype.h>
#include<algorithm>
#define int long long
using namespace std;
const int N=3e5+1;
int n,cnt,ans,a[N];
int vis[N],head[N],dep[N];
struct Edge{int nxt,to;}edge[N<<1];
struct node{
    int v;
    bool operator <(const node&x)const&{return a[x.v]+dep[x.v]<a[v]+dep[v];}
};
priority_queue<node> q;
void ins(int x,int y){
    edge[++cnt].nxt=head[x];
    edge[cnt].to=y;head[x]=cnt;
}
void dfs(int x,int fa){
    for(int i=head[x];i;i=edge[i].nxt){
        int y=edge[i].to;
        if(y==fa) continue;
        dep[y]=dep[x]+1;dfs(y,x);
    }
}
void bfs(){
    int tim=n;
    q.push((node){1});
    while(--tim>=0){
        int x=q.top().v;vis[x]=1;
        q.pop();ans=max(ans,tim+dep[x]+a[x]);
        for(int i=head[x];i;i=edge[i].nxt){
            int y=edge[i].to;
            if(!vis[y]) q.push((node){y});
        }
    }
}
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;
}
signed main(){
    freopen("practice.in","r",stdin);
    freopen("practice.out","w",stdout);
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<n;i++){
        int x=read(),y=read();
        ins(x,y),ins(y,x);
    }dfs(1,0);bfs();
    printf("%lld\n",ans);
    return 0;
}

T3

avatar

Solution:

我们考虑对于一个固定的\(C\)来说,有哪些最优的二元组\((A,B)\)

若存在一个\(X\),满足\(A<X<B\,\,and \,\,a_A<a_X\),那么\(X\)\(A\)更优,则\(a_A>a_X\)

若存在一个\(X\),满足\(A<X<B\,\,and\,\,a_B<a_X\),那么\(X\)\(B\)更优,则\(a_B>a_X\)

事实上,这样的二元组的数量为\(O(n)\),我们可以用一个单调栈来维护

在考虑如何处理询问,事实上我们可以从大到小枚举左端点,同时设\(f[i]\)表示当前已\(i\)作为\(C\)点的最大值

假设我们现在枚举到了\(i\)点,则我们把所有的以\(i\)作为\(A\)的二元组\((A,B)\)提出来

我们对所有的满足\(x>=B+(B-i)\)\(f[x]\)进行更新,同时处理所有以\(i\)\(l\)的询问

事实上这两个操作都可以用线段树进行简单维护,时间复杂度\(O((n+q)\,log_2\,n)\)

Code:

#include<iostream>
#include<cstdio>
#include<vector>
#include<ctype.h>
#include<algorithm>
using namespace std;
#define int long long
const int N=5e5+11;
int n,m,tp,a[N],sta[N];
int tr[N<<2],mx[N<<2],tag[N<<2],ans[N];
struct Q{int l,x,id;}ask[N];
inline bool cmp(Q x,Q y){return x.l<y.l;}
vector<int> use[N];
#define ls q<<1
#define rs q<<1|1
void update(int q){
    tr[q]=max(tr[ls],tr[rs]);
    mx[q]=max(mx[ls],mx[rs]);
}
void build(int q,int l,int r){
    if(l==r) return mx[q]=a[l],void();
    int mid=l+r>>1;
    build(ls,l,mid),build(rs,mid+1,r);
    update(q);
}
void pushdown(int q){
    if(!tag[q]) return ;
    tag[ls]=max(tag[ls],tag[q]);
    tag[rs]=max(tag[rs],tag[q]);
    tr[ls]=max(tr[ls],mx[ls]+tag[q]);
    tr[rs]=max(tr[rs],mx[rs]+tag[q]);
    tag[q]=0;
}
void change(int q,int l,int r,int L,int R,int v){
    if(l>=L&&r<=R){
        tr[q]=max(tr[q],v+mx[q]);
        tag[q]=max(tag[q],v);return ;
    }pushdown(q);
    int mid=l+r>>1;
    if(mid>=L) change(ls,l,mid,L,R,v);
    if(mid<R) change(rs,mid+1,r,L,R,v);
    update(q);
}
int query(int q,int l,int r,int L,int R){
    if(l>=L&&r<=R) return tr[q];
    int mid=l+r>>1,re=0;pushdown(q);
    if(mid>=L) re=max(re,query(ls,l,mid,L,R));
    if(mid<R) re=max(re,query(rs,mid+1,r,L,R));
    return re;
}
int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;
}
signed main(){
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<=n;i++){
        while(tp&&a[sta[tp]]<a[i])
            use[sta[tp]].push_back(i),--tp;
        for(int j=1;j<=tp;j++) use[sta[j]].push_back(i);
        sta[++tp]=i;
    }
    m=read();
    for(int i=1;i<=m;i++){
        int l=read(),r=read();
        ask[i]={l,r,i};
    }build(1,1,n);
    sort(ask+1,ask+m+1,cmp);
    int now=m;
    for(int i=n;i;i--){
        for(int j=0;j<use[i].size();j++){
            int y=use[i][j];
            if(2*y-i<=n) change(1,1,n,2*y-i,n,a[i]+a[y]);
        }
        while(now&&ask[now].l==i)
            ans[ask[now].id]=query(1,1,n,i,ask[now].x),--now;
    }
    for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/NLDQY/p/11666735.html
今日推荐