zoukankan      html  css  js  c++  java
  • 「2018山东一轮集训」 Tree

        为什么出题人这么毒瘤啊??!!一个分块还要带log的题非要出成n<=2*1e5。。。。。。。

        为了卡过最后两个点我做了无数常数优化,包括但不限于:把所有线段树改成 存差分的树状数组;把树剖求LCA的极小的log优化成rmq O(1)求LCA;根据测试情况手动调整siz的大小;

        但就是死也卡不过去,算了算了QWQ

    (常规套路,先把1设成根建有根树)

        这个题的主要思路就是 对节点的下标分块,设 f[i][j] 为 第i个块内所有点到点j的距离和,然后看如何快速的动态维护这个玩意。。。。

        发现改动一条边权的时候,只有两个点分别位于这条边两侧的时候才会对它们之间的dis有影响。

        我们设p为边端点中更深的那个,那么也就是一个在p子树内,一个在子树外的才有影响。。。。

        于是我们对每个块开一个vector记录一下这个块内的点的dfs序集合,排完序之后就可以之间O(log)的查询某个块在一棵子树内/外的点数了。。。

        因为f[][]的第一维比较小,所以我们可以暴力枚举第一维,然后对第二维进行快速的修改。。。。。这时候发现第二维如果是存dfs序的话会更加方便(子树内可以直接进行区间修改),所以就改成下标代表dfs序啦。。。

       

        对于整块整块的一些点到某个点的距离,用上述方法就行啦。。。可以发现都是区间修改单点查询,所以用差分的树状数组可以快(可能还不止)4倍常数哦。。。

       

        查询零散的点对(i,j)之间的距离的话更加简单。。可以动态维护dis[i]表示i到根的距离(发现也是区间修改单点查询,所以可以类似上述整块的方法处理),答案就是dis[i]+dis[j]-2*dis[LCA(i,j)]。。。

        可能说起来不是很多吧qwq?但是要写一辈子啊QWQWQWQ。。。。

        (我美好的下午就这么没了QWQ)

        话说我把树剖求LCA改成rmq之后反而更慢了QWQ,这是什么鬼啊。。。。

    /*
        inside : b * derta
        outside : a * derta
        
        all -> a * derta
        inside -> (b-a) * derta
    */
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<iostream>
    #define ll long long
    using namespace std;
    #define pb push_back
    const int maxn=200003,N=205;
    
    inline int read(){
    	int x=0; char ch=getchar();
    	for(;!isdigit(ch);ch=getchar());
    	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    	return x;
    }
    
    void W(ll x){ if(x>=10) W(x/10); putchar(x%10+'0');}
    
    int n,m,T,dep[maxn],siz[maxn],cl[maxn];
    int F[maxn],dc,dfn[maxn],dy[maxn],son[maxn];
    int bl[maxn],num,val[maxn*2],uu,vv,ww;
    int hd[maxn],ne[maxn*2],to[maxn*2];
    ll ans=0,f[N][maxn];
    vector<int> id[N];
    char s[10];
    
    void add(const int &x,const int &y,const int &z){
        to[++num]=y,ne[num]=hd[x],hd[x]=num,val[num]=z;
    }
    
    void update(const int &T,int x,const int &y){ for(;x<=n;x+=x&-x) f[T][x]+=(ll)y;}
    ll query(const int &T,int x){ ll an=0; for(;x;x-=x&-x) an+=(ll)f[T][x]; return an;}
    
    void Fdfs(int x,int fa){
    	F[x]=fa,siz[x]=1;
    	for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa){
    		dep[to[i]]=dep[x]+1,Fdfs(to[i],x),siz[x]+=siz[to[i]];
    		if(!son[x]||siz[to[i]]>siz[son[x]]) son[x]=to[i];
    	}
    }
    
    void Sdfs(int x,int tp){
    	dfn[x]=++dc,dy[dc]=x,cl[x]=tp;
    	
    	if(!son[x]) return;
    	
    	Sdfs(son[x],tp);
    	
    	for(int i=hd[x];i;i=ne[i])
    	    if(to[i]!=F[x]&&to[i]!=son[x]) Sdfs(to[i],to[i]);
    }
    
    inline int LCA(int a,int b){
    	while(cl[a]!=cl[b]){
    		if(dep[cl[a]]>dep[cl[b]]) a=F[cl[a]];
    		else b=F[cl[b]];
    	}
    	return dep[a]>dep[b]?b:a;
    }
    
    inline int Get(int T,int x){
        return upper_bound(id[T].begin(),id[T].end(),x)-id[T].begin();
    }
    
    inline void Maintain(int o,int derta){
    	int p=to[o*2-1];
    	if(dep[p]<dep[to[o<<1]]) p=to[o<<1];
    	
    	update(0,dfn[p],derta),update(0,dfn[p]+siz[p],-derta);
    	
    	for(int i=1,a,b;i<=200;i++) if(id[i].size()){
            a=Get(i,dfn[p]+siz[p]-1)-Get(i,dfn[p]-1),b=id[i].size()-a;
            update(i,1,a*derta),update(i,dfn[p],(b-a)*derta),update(i,dfn[p]+siz[p],(a-b)*derta);
    	}
    }
    
    inline ll calc(int qz,int p){
    	ll an=0;
    	
    	for(int i=1;i<bl[qz];i++) an+=query(i,dfn[p]);
    	
    	for(int i=qz;i;i--){
    		an+=query(0,dfn[i])+query(0,dfn[p])-2ll*query(0,dfn[LCA(p,i)]);
    		if(bl[i]!=bl[i-1]) break;
    	}
    	
    	return an;
    }
    
    inline void prework(){
    	Fdfs(1,0),Sdfs(1,1);
    	
    	for(int i=1;i<=n;i++){
    		bl[i]=(i-1)/1000+1;
    		id[bl[i]].pb(dfn[i]);
    	}
    	for(int i=1;i<=200;i++) sort(id[i].begin(),id[i].end());
    	
    	for(int i=1;i<n;i++) Maintain(i,val[i<<1]);
    }
    
    inline void solve(){
    	const int ha=n;
    	
    	while(m--){
            scanf("%s",s);
            if(s[0]=='m'){
            	uu=read(),vv=read();
            	if(T) uu^=ans,vv^=ans;
            	
            	Maintain(uu,vv-val[uu<<1]),val[uu<<1]=vv;
    		}
    		else{
    			uu=read(),vv=read(),ww=read();
    			if(T) uu^=ans,vv^=ans,ww^=ans;
    			
    			ans=calc(vv,ww)-calc(uu-1,ww);
    			
    			W(ans),puts(""),ans%=ha;
    		}
    	}
    }
    
    int main(){
    //	freopen("tree.in","r",stdin);
    //	freopen("tree.out","w",stdout);
    	
    	n=read(),m=read(),T=read();
    
    	for(int i=1;i<n;i++){
    		uu=read(),vv=read(),ww=read();
    		add(uu,vv,ww),add(vv,uu,ww);
    	}
    	
    	prework();
    	
    	solve();
    	
    	return 0;
    }
    
  • 相关阅读:
    ASP.NET身份验证机制membership入门——API篇
    测试SQL语句的执行时间
    ASP.NET身份验证机制membership入门——配置篇(2)
    ASP.NET身份验证机制membership入门——配置篇(1)
    ASP.NET身份验证机制membership入门——项目
    ASP.NET用户个性化设置Profile——配置1
    POJ 2762 强连通分量中存在单相连通边 【tarjan+toposort+缩点】.cpp
    POJ 2516 【最小费用最大流】.cpp
    POJ 1904 【强连通分量】.cpp
    POJ 1236 【强连通图+缩点】.cpp
  • 原文地址:https://www.cnblogs.com/JYYHH/p/9193078.html
Copyright © 2011-2022 走看看