zoukankan      html  css  js  c++  java
  • GDSOI 2019 day1 颜色

    一个和标算不同的做法
    题目中说所有颜色最多只会在询问中出现一次。
    注意到一个修改操作中,只有它包含的节点构成的虚树有贡献。
    对于一个修改操作,把所有它包含的颜色(设有(k)个)拿出来建虚树。
    这样子建虚树的节点数是(O(n))的。
    在虚树上,所有子树颜色个数(=k)的点都会对答案产生贡献。
    求出这些点可以扫描线+dfs序+树状数组(HH的项链)
    接下来求出这些点后,我们要把它的链并上的所有节点的权值+1。
    可以再用一个虚树,但是比较难写且常数大。
    可以使用树状数组维护。
    把所有点按照dfs序排序,把每个点处+val,相邻点的lca处-val即可。
    被卡常的代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define N 2000010
    #define int long long
    int n,m,h[N],v[N],nxt[N],ec,f[N],tp[N],p[N],sz[N],d[N],id[N],ct,st[N],ts,ss[N],tv,bt[N],nm,val,c[N],vi[N];
    void add(int x,int y){
    	v[++ec]=y;
    	nxt[ec]=h[x];
    	h[x]=ec;
    }
    void at(int x,int y){
    	for(;x<=n;x+=x&-x)
    		bt[x]+=y;
    }
    int lc(int x,int y){
    	while(tp[x]!=tp[y]){
    		if(d[tp[x]]<d[tp[y]])
    			y=f[tp[y]];
    		else
    			x=f[tp[x]];
    	}
    	if(d[x]<d[y])
    		return x;
    	return y;
    }
    int qu(int x){
    	int ans=0;
    	for(;x;x-=x&-x)
    		ans+=bt[x];
    	return ans;
    }
    vector<int>vc[N],vb[N];
    int cp(int x,int y){
    	return id[x]<id[y];
    }
    void d1(int x,int fa){
    	sz[x]=1;
    	f[x]=fa;
    	id[x]=++ct;
    	for(int i=h[x];i;i=nxt[i])
    		if(v[i]!=fa){
    			d[v[i]]=d[x]+1;
    			d1(v[i],x);
    			sz[x]+=sz[v[i]];
    			if(sz[p[x]]<sz[v[i]])
    				p[x]=v[i];
    		}
    }
    void d2(int x,int fa,int t){
    	tp[x]=t;
    	if(p[x])
    		d2(p[x],x,t);
    	for(int i=h[x];i;i=nxt[i])
    		if(v[i]!=fa&&v[i]!=p[x])
    			d2(v[i],x,v[i]);
    }
    void ins(int x){
    	if(!tp){
    		st[++ts]=x;
    		ss[++tv]=x;
    		return;
    	}
    	int ll=lc(x,st[ts]);
    	if(ll==st[ts]){
    		st[++ts]=x;
    		ss[++tv]=x;
    		return;
    	}
    	while(ts>1&&id[st[ts-1]]>=id[ll]){
    		vb[st[ts-1]].push_back(st[ts]);
    		//cerr<<st[ts-1]<<' '<<st[ts]<<'
    ';
    		ts--;
    	}
    	if(ll!=st[ts]){
    		ss[++tv]=ll;
    		vb[ll].push_back(st[ts]);
    		//cerr<<ll<<' '<<st[ts]<<'
    ';
    		st[ts]=ll;
    	}
    	st[++ts]=x;
    	ss[++tv]=x;
    }
    void bd(vector<int>x){
    	sort(x.begin(),x.end(),cp);
    	for(int i=0;i<x.size();i++)
    		ins(x[i]);
    	for(int i=2;i<=ts;i++){
    		vb[st[i-1]].push_back(st[i]);
    		//cerr<<st[i-1]<<' '<<st[i]<<'
    ';
    	}
    }
    struct qp{
    	int l,i;
    };
    struct dst{
    	int in[N],la[N],bt[N],sz[N],ct,va[N],st[N],sv[N],tp,tt;
    	vector<qp>qv[N];
    	void ad(int x,int y){
    		for(;x<=ct;x+=x&-x)
    			bt[x]+=y;
    	}
    	int qu(int x){
    		int ans=0;
    		for(;x;x-=x&-x)
    			ans+=bt[x];
    		return ans;
    	}
    	void dd(int x){
    		if(vi[x]){
    			in[x]=++ct;
    			st[ct]=x;
    			sz[x]=1;
    		}
    		else
    			in[x]=1e9;
    		ss[++tt]=x;
    		for(int i=0;i<vb[x].size();i++){
    			int y=vb[x][i];
    			dd(y);
    			sz[x]+=sz[y];
    			in[x]=min(in[x],in[y]);
    		}
    		qv[in[x]+sz[x]-1].push_back((qp){in[x],x});
    	}
    	void dt(){
    		for(int i=1;i<=ct;i++){
    			if(la[c[st[i]]])
    				ad(la[c[st[i]]],-1);
    			ad(i,1);
    			la[c[st[i]]]=i;
    			for(int j=0;j<qv[i].size();j++){
    				qp y=qv[i][j];
    				va[y.i]=qu(i)-qu(y.l-1);
    			}
    		}
    		tp=0;
    		for(int i=1;i<=tt;i++)
    			if(va[ss[i]]==nm)
    				sv[++tp]=ss[i];
    		sort(sv+1,sv+tp+1,cp);
    		for(int i=1;i<=tp;i++){
    			at(id[sv[i]],val);
    			if(i!=1)
    				at(id[lc(sv[i-1],sv[i])],-val);
    		}
    	}
    	void rb(){
    		for(int i=0;i<=ct;i++){
    			bt[i]=0;
    			qv[i].clear();
    		}
    		for(int i=1;i<=tp;i++)
    			sv[i]=0;
    		ct=tp=tt=0;
    		for(int i=1;i<=tv;i++){
    			in[ss[i]]=sz[ss[i]]=la[c[ss[i]]]=va[ss[i]]=vi[ss[i]]=st[i]=0;
    			vb[ss[i]].clear();
    		}
    	}
    }vg;
    int rd(){
    	int x=0;
    	char c=getchar();
    	while(!isdigit(c))
    		c=getchar();
    	while(isdigit(c)){
    		x=x*10+c-'0';
    		c=getchar();
    	}
    	return x;
    }
    signed main(){
    	freopen("color.in","r",stdin);
    	freopen("color.out","w",stdout);
    	scanf("%lld%lld",&n,&m);
    	for(int i=1;i<n;i++){
    		int x=rd(),y=rd();
    		x++;
    		y++;
    		add(x,y);
    		add(y,x);
    	}
    	d1(1,0);
    	d2(1,0,1);
    	for(int i=1;i<=n;i++){
    		c[i]=rd();
    		c[i]++;
    		vc[c[i]].push_back(i);
    	}
    	int la=0;
    	for(int i=1;i<=m;i++){
    		int op=rd();
    		if(op==1){
    			int p=rd();
    			vector<int>vs;
    			nm=p;
    			int ct=0;
    			for(int j=1;j<=p;j++){
    				int x=rd();
    				x=(x+la)%n;
    				x++;
    				for(int k=0;k<vc[x].size();k++){
    					ct+=vc[x].size();
    					vs.push_back(vc[x][k]);
    					vi[vc[x][k]]=1;
    				}
    			}
    			val=rd();
    			if(ct){
    				if(!vi[1])
    					vs.push_back(1);
    				bd(vs);
    				vg.dd(1);
    				vg.dt();
    			}
    			vg.rb();
    			ts=0;
    			tv=0;
    		}
    		else{
    			int x;
    			x=rd();
    			x=(x+la)%n;
    			x++;
    			printf("%lld
    ",la=qu(id[x]+sz[x]-1)-qu(id[x]-1));
    		}
    	}
    }
    
  • 相关阅读:
    homebrew 安装 mpv
    Spring JdbcTemplate 两种方法的区别
    git .gitignore失效的解决办法
    git 分支修改bug应用场景
    url编码实践
    escape encodeuri encodeURIComponent 区别
    mysql命令gruop by报错this is incompatible with sql_mode=only_full_group_by
    服务器病毒问题解决- 阿里云 挖矿病毒,Circle_MI.png
    trim和replace的陷阱实践
    mysql 5.7.15 union order by 子查询排序不生效
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/14106665.html
Copyright © 2011-2022 走看看