• 题解-【集训队作业2018】Simple Tree


    一道很无聊的题。出题人std写的是指令集暴力(

    先考虑序列上怎么做,首先瞎归约一下可以发现只有根号做法。然后考虑分块,对于每个块内维护一个有序的数组,这样查询修改都是 (O(sqrt{n}log{n})) 的。然后考虑优化。首先是散块修改,可以使用归并排序做到 (O(sqrt{n}))。然后查询考虑直接维护一个指针和连续段,每次只会跳一个连续段,也可以做到 (O(sqrt{n}))。考虑上树。可以直接套用zx论文中树分块的做法,但是这样要特殊处理子树询问。

    考虑树剖,直接做调整块大小是 (O(nsqrt{nlog n})) 的。然后有一个很神奇的优化(被lxl称作臭鱼烂虾分块),对每个重链分别做序列上的情况,块大小为重链长度开根。然后由于重链一定会翻倍,所以复杂度就对了。然后考虑子树查询,发现一定是一堆连续的完整重链,于是再搞个什么线段树就好了。复杂度 (O(nsqrt{n}+nlog^2{n}))

    #include<bits/stdc++.h>
    #define pii std::pair<int,int>
    #define mp std::make_pair
    #define F first
    #define S second
    const int maxn=200005;
    template<typename T>
    inline void read(T &x){
    	T flag=1;
    	char ch=getchar();
    	for(;!isdigit(ch);ch=getchar())if(ch=='-')flag=-1;
    	for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';
    	x*=flag;
    }
    template<typename T>
    inline void write(T x){
    	if(x==0)return putchar('0'),void();
    	int stkk[20],ttop=0;
    	while(x){
    		stkk[++ttop]=x%10;
    		x/=10;
    	}
    	for(int i=ttop;i>=1;i--)putchar(stkk[i]+'0');
    }
    template<typename T>
    inline void print(T x){
    	if(x<0)putchar('-'),x=-x;
    	write(x);
    	putchar('
    ');
    }
    bool _;
    int sum[maxn<<2];
    inline void push_up(int p){
    	sum[p]=sum[p<<1]+sum[p<<1|1];
    }
    void cc(int p,int l,int r,int ppos,int v){
    	if(l==r)return sum[p]=v,void();
    	int mid=(l+r)>>1;
    	if(ppos<=mid)cc(p<<1,l,mid,ppos,v);
    	else cc(p<<1|1,mid+1,r,ppos,v);
    	push_up(p);
    }
    int qq(int p,int l,int r,int x,int y){
    	if(l>y||r<x)return 0;
    	if(x<=l&&r<=y)return sum[p];
    	int mid=(l+r)>>1;
    	return qq(p<<1,l,mid,x,y)+qq(p<<1|1,mid+1,r,x,y);
    }
    struct node{
    	int pre,to;
    }edge[maxn<<1];
    int head[maxn],tttot=1;
    int n,m,T,lastans,fa[maxn],dep[maxn],top[maxn],dfn[maxn],pos[maxn],Dfn,sz[maxn],son[maxn],lst[maxn];
    int bel[maxn],L[maxn],R[maxn],tag[maxn],pp[maxn],ss[maxn],yy[maxn],tmp[maxn],B[maxn],len[maxn],tot;;
    pii w[maxn],s1[maxn],s2[maxn];
    bool __;
    inline void add_edge(int u,int v){
    	edge[++tttot]=node{head[u],v};
    	head[u]=tttot;
    }
    void dfs1(int u){
    	sz[u]=1;
    	for(int i=head[u];i;i=edge[i].pre){
    		int v=edge[i].to;
    		if(v==fa[u])continue;
    		fa[v]=u;
    		dep[v]=dep[u]+1;
    		dfs1(v);
    		sz[u]+=sz[v];
    		if(sz[v]>sz[son[u]])son[u]=v;
    	}
    }
    void dfs2(int u,int chain){
    	top[u]=chain;
    	dfn[pos[u]=++Dfn]=u;
    	if(son[u])dfs2(son[u],chain);
    	for(int i=head[u];i;i=edge[i].pre){
    		int v=edge[i].to;
    		if(v==son[u]||v==fa[u])continue;
    		dfs2(v,v);
    	}
    	lst[u]=Dfn;
    	if(u==chain){
    		for(int x=u;x;x=son[x])len[u]++;
    		B[u]=std::max(1,int(sqrt(len[u]*0.6)));
    		for(int i=pos[u],j=B[u];i<=pos[u]+len[u]-1;i++){
    			if(j>=B[u])
    				tot++,j=1,bel[i]=tot,L[tot]=i,R[tot]=i;
    			else
    				j++,bel[i]=tot,R[tot]=i;
    		}
    	}
    }
    inline void calc(int id){
    	pp[id]=R[id]+1;
    	for(int i=R[id];i>=L[id];i--)
    		if(w[i].F>0)
    			pp[id]=i;
    	for(int i=L[id],j=i;i<=R[id];i=j+1){
    		if(i==L[id]||w[i].F!=w[i-1].F){
    			for(j=i+1;j<=R[id];j++)
    				if(w[j].F!=w[i].F)
    					break;
    			j--;
    			for(int k=i;k<=j;k++)
    				ss[k]=i,yy[k]=j;
    		}
    	}
    }
    inline void build(int id){
    	std::sort(w+L[id],w+R[id]+1);
    	calc(id);
    }
    inline void modify(int id,int l,int r,int v){
    	if(v==0&&tag[id]==0)return;
    	int t1=0,t2=0;
    	for(int i=L[id];i<=R[id];i++)
    		w[i].F+=tag[id];
    	tag[id]=0;
    	for(int i=L[id];i<=R[id];i++){
    		if(l<=w[i].S&&w[i].S<=r)
    			w[i].F+=v,s2[++t2]=w[i];
    		else s1[++t1]=w[i];
    	}
    	int r1=1,r2=1;
    	for(int i=L[id];i<=R[id];i++)
    		if(r1<=t1&&r2<=t2)
    			w[i]=s1[r1]<s2[r2]?s1[r1++]:s2[r2++];
    		else if(r1<=t1)
    			w[i]=s1[r1++];
    		else if(r2<=t2)
    			w[i]=s2[r2++];
    	calc(id);
    }
    inline int ask(int id,int l,int r){
    	modify(id,-1,-1,0);
    	int res=0;
    	for(int i=L[id];i<=R[id];i++)
    		if(l<=w[i].S&&w[i].S<=r)
    			if(w[i].F>0)
    				res++;
    	return res;
    }
    inline int askh(int id){
    	return R[id]-pp[id]+1;
    }
    inline void change(int id,int v){
    	tag[id]+=v;
    	if(v==1){
    		if(pp[id]==L[id])return;
    		if(tag[id]+w[pp[id]-1].F>0)
    			pp[id]=ss[pp[id]-1];
    	}else if(v==-1){
    		if(pp[id]==R[id]+1)return;
    		if(tag[id]+w[pp[id]].F<=0)
    			pp[id]=yy[pp[id]]+1;
    	}
    }
    inline void modify_s(int l,int r,int v){
    	if(bel[l]==bel[r]){
    		modify(bel[l],l,r,v);
    	}else{
    		modify(bel[l],l,R[bel[l]],v);
    		modify(bel[r],L[bel[r]],r,v);
    		for(int i=bel[l]+1;i<bel[r];i++)
    			change(i,v);
    	}
    }
    inline int qry(int l,int r){
    	int res=0;
    	if(bel[l]==bel[r]){
    		res+=ask(bel[l],l,r);
    	}else{
    		res+=ask(bel[l],l,R[bel[l]]);
    		res+=ask(bel[r],L[bel[r]],r);
    		for(int i=bel[l]+1;i<bel[r];i++)
    			res+=askh(i); 
    	}
    	return res;
    }
    int main(){
    //	freopen("2.in","r",stdin);
    //	freopen("2.out","w",stdout);
    //	std::cout<<(((long long)&_-(long long)&__)>>20)<<"
    ";
    	read(n);read(m);read(T);
    	for(int i=1,u,v;i<n;i++){
    		read(u);read(v);
    		add_edge(u,v);add_edge(v,u);
    	}
    	for(int i=1;i<=n;i++)
    		read(tmp[i]);
    	dfs1(1);dfs2(1,1);
    	for(int i=1;i<=n;i++)
    		w[i]=mp(tmp[dfn[i]],i);
    	for(int i=1;i<=tot;i++)build(i);
    	for(int i=1;i<=n;i++){
    		if(i==top[i]){
    			int ccc=qry(pos[i],pos[i]+len[i]-1);
    			cc(1,1,n,pos[i],ccc);
    		}
    	}
    	while(m--){
    		int op,x,y,r;
    		read(op);read(x);x^=lastans;
    		if(op==1){
    			read(y);read(r);
    			y^=lastans;
    			int u=x,v=y;
    			while(top[u]!=top[v]){
    				if(dep[top[u]]<dep[top[v]])std::swap(u,v);
    				modify_s(pos[top[u]],pos[u],r);
    				int ccc=qry(pos[top[u]],pos[top[u]]+len[top[u]]-1);
    				cc(1,1,n,pos[top[u]],ccc);
    				u=fa[top[u]];
    			}
    			if(dep[u]>dep[v])std::swap(u,v);
    			modify_s(pos[u],pos[v],r);
    			int ccc=qry(pos[top[u]],pos[top[u]]+len[top[u]]-1);
    			cc(1,1,n,pos[top[u]],ccc);
    		}else if(op==2){
    			read(y);
    			y^=lastans;
    			int u=x,v=y,ans=0;
    			while(top[u]!=top[v]){
    				if(dep[top[u]]<dep[top[v]])std::swap(u,v);
    				ans+=qry(pos[top[u]],pos[u]);
    				u=fa[top[u]];
    			}
    			if(dep[u]>dep[v])std::swap(u,v);
    			ans+=qry(pos[u],pos[v]);
    			print(ans);
    			if(T==1)lastans=ans;
    		}else{
    			int ans=qry(pos[x],pos[top[x]]+len[top[x]]-1)+qq(1,1,n,pos[top[x]]+len[top[x]],lst[x]);
    			print(ans); 
    			if(T==1)lastans=ans;
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    列表基本操作——1
    条件判断与嵌套
    数据拼接与数据转换
    变量与赋值
    打印数与type()函数
    print()函数与打印字符串
    arduino开发ESP8266学习笔记二----按键控制LED灯
    arduino开发ESP8266学习笔记一 ----点亮一个LED灯
    无线充电
    EMC设计总结
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/15496886.html
Copyright © 2020-2023  润新知