zoukankan      html  css  js  c++  java
  • BZOJ 2959 长跑

    题目链接:长跑

      这道题要求维护一张图,有三个操作:

      1.在(u),(v)之间加入一条边;

      2.把(u)点的权值修改为(v);

      3.要求把所有边定向,询问从(u)到(v)的路径可以经过的最大点权和。路径可以是非简单路径,同一个点权值只算一次。

      首先可以发现如果形成了一个边双,那么这个边双内的所有点的贡献就都可以一起算上了。所以每次加边的时候,如果形成了一个边双,那么就暴力把他们给合并了,每次就只需要询问路径点权和了。这个用(LCT)维护即可。缩点的时候可以用并查集维护一下每个点缩点后所属的点。复杂度(O(malpha(n)log n))

      还有一种树链剖分的做法。我们可以先离线构出树,那么同理,如果某次操作后出现了边双,我们就可以直接把这些点的权值集中到(lca),其余位置清(0)。用(LCT)实现这个也是可以的,但是用树链剖分套树状数组会更快。复杂度(O(mlog n))或者(O(mlog^2 n))

      下面贴代码(第一种做法):

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
    #define isroot(x) (x!=s[fa[x]][0] && x!=s[fa[x]][1])
    #define maxn 150010
    
    using namespace std;
    typedef long long llg;
    
    int n,m,val[maxn],sumv[maxn],a[maxn];
    int fa[maxn],s[maxn][2],d[maxn];
    int f1[maxn],f2[maxn],s1[maxn],s2[maxn];
    bool rev[maxn];
    
    int getint(){
    	int w=0;bool q=0;
    	char c=getchar();
    	while((c>'9'||c<'0')&&c!='-') c=getchar();
    	if(c=='-') c=getchar(),q=1;
    	while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
    	return q?-w:w;
    }
    
    int fi1(int x){return f1[f1[x]]==f1[x]?f1[x]:f1[x]=fi1(f1[x]);}
    int fi2(int x){return f2[f2[x]]==f2[x]?f2[x]:f2[x]=fi2(f2[x]);}
    void update(int u){sumv[u]=sumv[s[u][0]]+sumv[s[u][1]]+val[u];}
    void R(int u){
        int p=fa[u],g=fa[p];
        bool l=(u==s[p][1]),r=!l;
        if(!isroot(p)) s[g][p==s[g][1]]=u;
        fa[s[u][r]]=p; s[p][l]=s[u][r];
        s[u][r]=p; fa[p]=u; fa[u]=g;
        update(p); update(u);
    }
     
    void splay(int u){
        int ld=0; d[ld=1]=u;
        for(int i=u;!isroot(i);i=fa[i]) d[++ld]=fa[i];
        for(int i=ld,x;x=d[i],i;i--)
            if(rev[x]){
                rev[s[x][0]]^=1,rev[s[x][1]]^=1;
                swap(s[x][0],s[x][1]); rev[x]=0;
            }
        while(!isroot(u)){
            int p=fa[u],g=fa[p];
            if(!isroot(p)){
                if((u==s[p][1])^(p==s[g][1])) R(u);
                else R(p);
            }
            R(u);
        }
    }
    
    void access(int u){
    	for(int t=0;u;t=u,u=fa[u]=fi1(fa[u]))
    		splay(u),s[u][1]=t,update(u);
    }
    
    void makert(int u){access(u); splay(u); rev[u]^=1;}
    void merge(int x,int y){
    	x=fi1(x),y=fi1(y);
    	if(s1[x]>s1[y]) x^=y^=x^=y;
    	f1[x]=y; s1[y]+=s1[x];
    }
    
    void dfs(int u,int fa){
    	if(u!=fa) merge(u,fa);
    	if(s[u][0]) dfs(s[u][0],u);
    	if(s[u][1]) dfs(s[u][1],u);
    }
    
    int main(){
    	File("a");
    	n=getint(),m=getint();
    	for(int i=1;i<=n;i++){
    		a[i]=val[i]=sumv[i]=getint();
    		f1[i]=f2[i]=i,s1[i]=s2[i]=1;
    	}
    	while(m--){
    		int op=getint(),u=getint(),v=getint();
    		if(op==1){
    			if(fi2(u)!=fi2(v)){
    				makert(fi1(u)),fa[fi1(u)]=fi1(v);
    				u=fi2(u),v=fi2(v);
    				if(s2[u]>s2[v]) u^=v^=u^=v;
    				s2[v]+=s2[u]; f2[u]=v;
    			}
    			else if(fi1(u)!=fi1(v)){
    				makert(u=fi1(u)); v=fi1(v);
    				access(v),splay(v); dfs(v,v); splay(v=fi1(v));
    				val[v]=sumv[v]; s[v][0]=s[v][1]=0;
    			}
    		}
    		else if(op==2){
    			int x=fi1(u); makert(x); val[x]+=v-a[u];
    			sumv[x]+=v-a[u]; a[u]=v;
    		}
    		else if(op==3)
    			if(fi2(u)!=fi2(v)) printf("-1
    ");
    			else{
    				u=fi1(u); v=fi1(v);
    				makert(u),access(v),splay(v);
    				printf("%d
    ",sumv[v]);
    			}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Tcp抓包以及Tcp状态
    Wireshark抓包使用指南
    服务端tcp syn无响应,无回复
    升级openssh
    平滑升级Nginx
    Memcached 未授权访问漏洞修复
    服务端高并发分布式架构演进之路
    es索引查询与删除
    申请elasticsearch中x-pack插件许可证及授权
    独立安装ab压力测试工具及测试nginx性能
  • 原文地址:https://www.cnblogs.com/lcf-2000/p/6624179.html
Copyright © 2011-2022 走看看