• 模板(ac)


    谢天谢地!

    首先鸣谢人帅话骚的好心人lyd的细心指导,lnc提壶灌顶的思维引导,耗时1.5天,我。。终于调过了

    好,步入正题:

    30%

      暴搜,不解释

    #include<bits/stdc++.h>
    #define int long long
    #define MAXN 100010
    using namespace std;
    inline int read(){
    	int s=0,w=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar(); }
    	while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
    	return s*w;
    }
    #define kd read()
    map<int ,bool >mp[MAXN];
    struct rr{
    	int nt,to;
    }bl[MAXN<<1];int hd[MAXN],itot;
    void add(int x,int y){
    	bl[++itot].to=y;
    	bl[itot].nt=hd[x];
    	hd[x]=itot;
    }
    int n,m,Q;
    int lis[MAXN];
    int qx[MAXN],qc[MAXN];
    int fat[MAXN],zui[MAXN],lim[MAXN],sm[MAXN];
    void dfs(int u,int fa){
    	fat[u]=fa;
    	for(int i=hd[u];i;i=bl[i].nt){
    		if(bl[i].to==fa)continue;
    		dfs(bl[i].to,u);
    	}
    }
    void work(int pos,int c){
    	for(int i=pos;i;i=fat[i]){
    		++sm[i];
    		if(sm[i]>lim[i]) continue;
    		if(!mp[i][c]) ++zui[i];
    		mp[i][c]=1;
    	}
    }
    signed main(){
    //	freopen("da.in","r",stdin);
    	n=kd;
    	for(int i=1,a,b;i<n;++i){
    		a=kd;b=kd;
    		add(a,b);add(b,a);
    	}
    	for(int i=1;i<=n;++i)
    		lim[i]=kd;
    	dfs(1,0);	
    	m=kd;
    	for(int i=1;i<=m;++i){
    		qx[i]=kd;qc[i]=kd;
    		lis[i]=qc[i];	
    	}
    	sort(lis+1,lis+m+1);
    	int lcnt=unique(lis+1,lis+m+1)-(lis+1);
    	for(int i=1;i<=m;++i){
    		qc[i]=lower_bound(lis+1,lis+lcnt+1,qc[i])-lis;
    		work(qx[i],qc[i]);
    	}
    	Q=kd;
    	int x;
    	while(Q){
    		--Q;
    		x=kd;
    		printf("%lld
    ",zui[x]);
    	}
    }
    

     70%

      出题人是真的好心,造了40%的无脑差分的数据(和雨天的尾巴一样)。

    #include<cstdio>
    #include<iostream>
    #include<map>
    #define go(i) for(int i=head[x];i;i=nxt[i])if(to[i]!=fa[x])
    #define lch ch[now][0]
    #define rch ch[now][1]
    #define N 100005
    using namespace std;
    
    int n,m,num_bian,Q,num_map,tot,Mi=0x3f3f3f3f;
    int head[N],nxt[N<<1],to[N<<1],t[N],fa[N],buc[1005][1005];
    int ch[N*50][2],sum[N*50],ret[N],rt[N];//树上差分,空间复杂度O(mlogm),每次多一个链为log,有m次修改是mlogm
    map<int,int>turn;
    
    inline void add(int x,int y){
    	to[++num_bian]=y;nxt[num_bian]=head[x];head[x]=num_bian;
    }
    inline void Dfs(int x){go(i) fa[to[i]]=x,Dfs(to[i]);}
    inline void change(int &now,int l,int r,int x){
    	if(!now) now=++tot;
    	if(l==r)return (void)(sum[now]=1);
    	int mid=(l+r)>>1;
    	if(x<=mid)change(lch,l,mid,x);
    	else change(rch,mid+1,r,x);
    	sum[now]=sum[lch]+sum[rch];
    }
    inline int merge(int x,int y,int l,int r){
    	if(!x||!y) return x+y;
    	if(l==r) return x;
    	int mid=(l+r)>>1;
    	ch[x][0]=merge(ch[x][0],ch[y][0],l,mid);
    	ch[x][1]=merge(ch[x][1],ch[y][1],mid+1,r);
    	sum[x]=sum[ch[x][0]]+sum[ch[x][1]];
    	/*printf("l:%d r:%d sum:%d
    ",l,r,sum[x]);
    	printf("sum[rt[3]]=%d
    ",sum[rt[3]]);*/
    	return x;
    }
    inline void Dfs1(int x){go(i) Dfs1(to[i]),rt[x]=merge(rt[x],rt[to[i]],1,m);ret[x]=sum[rt[x]];}
    int main(){
    	scanf("%d",&n);
    	for(int i=1,x,y;i<=n-1;++i) scanf("%d%d",&x,&y),add(x,y),add(y,x);
    	for(int i=1;i<=n;++i)scanf("%d",&t[i]),Mi=min(Mi,t[i]);Dfs(1);
    	if(Mi!=1e5){
    		scanf("%d",&m);
    		for(int i=1,x,col;i<=m;++i)
    		{scanf("%d%d",&x,&col);while(1){if(!x)break;if(t[x]>0){t[x]--;if(!buc[x][col]) buc[x][col]=1,buc[x][0]++;}x=fa[x];}}
    		scanf("%d",&Q);for(int i=1,x;i<=Q;++i)scanf("%d",&x),printf("%d
    ",buc[x][0]);return 0;
    	}
    	else{
    		scanf("%d",&m);
    		for(int i=1,pos,color;i<=m;++i){
    			scanf("%d%d",&pos,&color);
    			(turn.find(color)==turn.end()?turn[color]=++num_map:0);
    			color=turn[color];change(rt[pos],1,m,color);
    		}
    		Dfs1(1);scanf("%d",&Q);
    		for(int i=1,x;i<=Q;++i)scanf("%d",&x),printf("%d
    ",ret[x]);return 0;
    	}
    }
    

     100%

      一个很厉害的思路,我一直局限在以球的种类为下标建树,但其实忽略了一个很有用的性质:一个节点在一个时刻最多只有一个球。也就是启发我们以时间为下标,只考虑这一时刻是否有球,或是否球有贡献。这样可以能兼顾到70%的忽略时间影响的问题。

      1.来自lnc的只建一棵树作为一个全局变量,运用启发式合并,考虑重儿子(操作数最多的节点)的树不清继承给父亲最优,开vector存每个节点的操作.

    对于每一个节点,用一个线段树,下标为时间,存储这个时间
    子树中是否加入了小球,这个小球对答案的贡献(如果之前有
    这种颜色的小球贡献就是 0 )。
    在线段树上二分就能求出这个节点的答案。
    维护这棵线段树可以用启发式合并的方法。
    用启发式合并的方式处理出当前子树中的所有操作,同时构建
    出线段树。
    
    #include<bits/stdc++.h>
    #define MAXN 100100
    #define TR (MAXN<<2)
    using namespace std;
    int n,m,Q;
    map<int ,int >lis;int lcnt;
    vector<int >tt[MAXN],cc[MAXN];
    int sz[MAXN],son[MAXN],zui[MAXN],lim[MAXN];
    int sm[TR],knd[TR],lb[TR];
    #define ls (u<<1)
    #define rs (u<<1|1)
    int mp[MAXN];
    struct rr{
    	int nt,to;
    }bl[MAXN<<1];int hd[MAXN],itot;
    void add(int x,int y){
    	bl[++itot].to=y;
    	bl[itot].nt=hd[x];
    	hd[x]=itot;
    }
    void dfs(int u,int fa){
    	sz[u]+=tt[u].size();
    	for(int i=hd[u];i;i=bl[i].nt){
    		if(bl[i].to==fa)continue;
    		dfs(bl[i].to,u);
    		sz[u]+=sz[bl[i].to];
    		if(sz[son[u]]<sz[bl[i].to])
    			son[u]=bl[i].to;
    	}
    }
    void down(int u){
    	if(!lb[u])return ;
    	sm[ls]=sm[rs]=0;
    	knd[ls]=knd[rs]=0;
    	lb[ls]=lb[rs]=1;
    	lb[u]=0;
    }
    void up(int u){
    	sm[u]=sm[ls]+sm[rs];
    	knd[u]=knd[ls]+knd[rs];
    }
    void upd(int u,int l,int r,int pos,int v1,int v2){
    	down(u);
    	if(l==r){
    		sm[u]+=v1;
    		knd[u]+=v2;
    		return ;
    	}
    	int mid=l+r>>1;
    	if(pos<=mid)upd(ls,l,mid,pos,v1,v2);
    	else upd(rs,mid+1,r,pos,v1,v2);
    	up(u);
    }
    int query(int u,int l,int r,int xa){
    	down(u);
    	if(xa<=0)return 0;
    	if(l==r)return knd[u];
    	int mid=l+r>>1;
    	if(xa>=sm[ls]){
    		int lsm=knd[ls];
    		lsm+=query(rs,mid+1,r,xa-sm[ls]);
    		return lsm;
    	}
    	return query(ls,l,mid,xa);
    }
    void insert(int u){
    	int tim,co;
    	for(int k=0;k<tt[u].size();++k){
    		tim=tt[u][k];co=cc[u][k];
    		if(!mp[co])upd(1,1,m,(mp[co]=tim),1,1);
    		else if(mp[co]>tim){
    			upd(1,1,m,mp[co],0,-1);
    			upd(1,1,m,(mp[co]=tim),1,1);
    		}
    		else upd(1,1,m,tim,1,0);
    	}	
    }
    void zy(int x,int y){
    	for(int k=0;k<tt[y].size();++k){
    		tt[x].push_back(tt[y][k]);
    		cc[x].push_back(cc[y][k]);
    	}
    	tt[y].clear();cc[y].clear();
    }
    void shan(int u){
    	sm[1]=knd[1]=0;
    	lb[1]=1;
    	down(1);
    	for(int k=0;k<cc[u].size();++k)
    		mp[cc[u][k]]=0;
    }
    void sou(int u,int fa){
    	//cout<<u<<" "<<fa<<endl;
    	for(int i=hd[u];i;i=bl[i].nt){
    		if(bl[i].to==fa)continue;
    		if(bl[i].to==son[u])continue;
    		sou(bl[i].to,u);
    		shan(bl[i].to);
    	}
    	if(son[u])sou(son[u],u);
    	insert(u);
    	for(int i=hd[u];i;i=bl[i].nt){
    		if(bl[i].to==fa)continue;
    		if(bl[i].to==son[u])continue;
    		insert(bl[i].to);
    	}
    	zui[u]=query(1,1,m,lim[u]);
    	if(son[u]){
    		zy(son[u],u);
    		swap(tt[son[u]],tt[u]);
    		swap(cc[son[u]],cc[u]);
    		for(int i=hd[u];i;i=bl[i].nt){
    			if(bl[i].to==fa)continue;
    			if(bl[i].to==son[u])continue;
    			zy(u,bl[i].to);
    		}
    	}
    }
    int main(){
    	//freopen("da.in","r",stdin);
    	scanf("%d",&n);
    	for(int i=1,a,b;i<n;++i){
    		scanf("%d%d",&a,&b);
    		add(a,b);add(b,a);
    	}
    	for(int i=1;i<=n;++i)
    		scanf("%d",&lim[i]);
    	scanf("%d",&m);
    	for(int i=1,x,c;i<=m;++i){
    		scanf("%d%d",&x,&c);
    		if(!lis[c])lis[c]=++lcnt;
    		tt[x].push_back(i);
    		cc[x].push_back(lis[c]);
    	}
    	sz[0]=-1;
    	dfs(1,0);
    	//for(int i=1;i<=n;++i)
    	//	printf("sz[%d]=%d
    ",i,sz[i]);
    	sou(1,0);
    	scanf("%d",&Q);
    	int x;
    	while(Q){
    		--Q;
    		scanf("%d",&x);
    		printf("%d
    ",zui[x]);
    	}
    }
    

      O(n*(logn^2))插入为logn,询问logn,操作数n

      2.仍然可以动态开点,尽管最多建叶子节点数棵树,但动态开点还是有空间保证的,然而没调出来就弃了,现%whs和lockey

    然而whs的码风太丑,还是粘lockey的吧

    #include<iostream>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<algorithm>
    #include<map>
    using namespace std;
    int n,m,Q,num,cet,root;
    const int maxn=1e5+100;
    int ls[410000],rs[410000],f[410000],qiunum[410000],colornum[410000],w[maxn],size[maxn],ma[maxn],is_here[maxn],loc[maxn],wolan[maxn],key[maxn];
    vector<int>son[110000],point[110000];
    int tmp[maxn],ans[maxn];
    inline void down(int t){
    	qiunum[ls[t]]=colornum[ls[t]]=0;
    	qiunum[rs[t]]=colornum[rs[t]]=0;
    	f[ls[t]]=f[rs[t]]=1;
    	if(ls[ls[t]]==0&&rs[ls[t]]==0) f[ls[t]]=0;
    	if(ls[rs[t]]==0&&rs[rs[t]]==0) f[rs[t]]=0;
    	f[t]=0;
    }
    inline void build(int  &t,int l,int r){
    	if(!t) t=++cet;
     	if(l==r) return ;
    	int mid=(l+r)/2;
    	build(ls[t],l,mid);
    	build(rs[t],mid+1,r);
    }
    inline void dfs1(int x,int pre){
    	size[x]=1+point[x].size();
    	int mxn=0;
    	for(register int i=0;i<son[x].size();i++){
    		int y=son[x][i];
    		if(y==pre) continue;
    		dfs1(y,x);
    		size[x]+=size[y];
    		if(size[y]>mxn) ma[x]=y,mxn=size[y];
    	}
    }
    inline void change(int t,int l,int r,int x){
    	if(l==r){
    		colornum[t]=0;
    		return;
    	}
    	if(f[t]) down(t);
    	int mid=(l+r)/2;
    	if(mid>=x) change(ls[t],l,mid,x);
    	else change(rs[t],mid+1,r,x);
    	qiunum[t]=qiunum[ls[t]]+qiunum[rs[t]];
    	colornum[t]=colornum[ls[t]]+colornum[rs[t]];
    }
    int landenum;
    inline void add(int t,int l,int r,int x,int k){
    	if(l==r){
    		qiunum[t]+=k;
    		colornum[t]+=k;
    		if(wolan[w[l]]!=landenum) wolan[w[l]]=0,is_here[w[l]]=0,loc[w[l]]=0;
    		if(k==1&&!is_here[w[l]]) is_here[w[l]]=1,loc[w[l]]=l,wolan[w[l]]=landenum;
    		else if(k==1&&is_here[w[l]]){
    			if(loc[w[l]]<l)  colornum[t]=0;
    			else{
    				change(1,1,m,loc[w[l]]);
    				loc[w[l]]=l;
    			}
    		}
    		return;
    	}
    	if(f[t]) down(t);
    	int mid=(l+r)/2;
    	if(mid>=x) add(ls[t],l,mid,x,k);
    	else add(rs[t],mid+1,r,x,k);
    	qiunum[t]=qiunum[ls[t]]+qiunum[rs[t]];
    	colornum[t]=colornum[ls[t]]+colornum[rs[t]];
    }
    inline void go_add(int x,int pre,int k){
    	for(register int i=0;i<point[x].size();i++)
    		add(1,1,m,point[x][i],k);
    	for(register int i=0;i<son[x].size();i++)
    		 if(son[x][i]!=pre)
    		 	 go_add(son[x][i],x,k);
    }
    inline int ask(int t,int x){
    	if(x==0) return 0;
    	if(qiunum[t]==0) return 0;
    	if(t==0) return 0;
    	if(qiunum[t]<x) return colornum[t];
    	if(qiunum[t]==x) return colornum[t];
    	if(qiunum[ls[t]]==x) return colornum[ls[t]];
    	else if(qiunum[ls[t]]>x) return ask(ls[t],x);
    	return colornum[ls[t]]+ask(rs[t],x-qiunum[ls[t]]);
    }
    inline void dfs(int x,int keep,int pre){
    	landenum++;
    	for(register int i=0;i<son[x].size();i++){
    		int y=son[x][i];
    		if(y==pre||y==ma[x]) continue;
    		dfs(y,0,x);
    	}
    	if(ma[x]) dfs(ma[x],1,x);
    	for(register int i=0;i<point[x].size();i++)
    		add(1,1,m,point[x][i],1);
    	for(register int i=0;i<son[x].size();i++){
    		int y=son[x][i];
    		if(y==pre||y==ma[x]) continue;
    		go_add(son[x][i],x,1);
    	}
    	ans[x]=ask(1,tmp[x]);
    	if(!keep){
    		f[1]=1,qiunum[1]=0,colornum[1]=0;
    	}
    }
    int main(){
    	scanf("%d",&n);
    	int  x,y;
    	for(register int i=1;i<n;i++){
    		scanf("%d%d",&x,&y);
    		son[x].push_back(y);
    		son[y].push_back(x);
    	}
    	for(register int i=1;i<=n;i++)
    		scanf("%d",&tmp[i]);
    	scanf("%d",&m);
    	build(root,1,m);
    	for(register int i=1;i<=m;i++){
    		scanf("%d%d",&x,&y);
    		w[i]=key[i]=y;
    		point[x].push_back(i);
    	}
    	cout<<endl;
    	sort(key+1,key+m+1);
    	int q=unique(key+1,key+m+1)-key- 1;
    	for(register int i=1;i<=m;i++){
    		w[i]=lower_bound(key+1,key+q+1,w[i])-key;
    	}
    	dfs1(1,0);
    	dfs(1,0,0);
    	scanf("%d",&Q);
    	while(Q--){
    		scanf("%d",&x);
    		printf("%d
    ",ans[x]);
    	}
    	return 0;
    }
    

     补充:一颗线段树的做法中一定要把vector清掉,虽然O(N)费时间,但如果vector过于膨胀,会暴掉...

  • 相关阅读:
    以最少的循环把两个数组里面的相同结果输出来
    解决PL/SQL Developer连接数据库时出现 “ORA-12541:TNS:无监听程序”错误
    AOP中Advice执行两遍的原因
    Java注释@interface的用法
    Spring进阶教程之在ApplicationContext初始化完成后重定义Bean
    Java的注解机制——Spring自动装配的实现原理
    基数排序简单Java实现
    jQuery的选择器中的通配符
    SEO 网站页面SEO优化之页面title标题优化
    IntelliJ IDEA 中文乱码解决
  • 原文地址:https://www.cnblogs.com/2018hzoicyf/p/11276015.html
Copyright © 2020-2023  润新知