zoukankan      html  css  js  c++  java
  • 「HNOI2016」数据结构大毒瘤

    真是 (6) 道数据结构毒瘤。。。

    开始口胡各种做法。。。

    「HNOI2016」网络

    整体二分+树状数组。

    开始想了一个大常数 (O(nlog^2 n)) 做法,然后就被卡掉了。。。

    发现直接维护一定是 (O(nlog^3 n)) 的,所以我当时选择了用 (LCT) 维护树上路径,跑起来比树剖可能都慢。。。

    其实路径加单点查可以直接在 (dfs) 序上弄树状数组的,虽然也是 (O(nlog^2 n)) 的,但是肯定能通过此题。。。

    (Code Below:)

    #include <bits/stdc++.h>
    #define lowbit(x) ((x)&(-(x)))
    using namespace std;
    const int maxn=100000+10;
    const int maxm=200000+10;
    int n,m,qn,c[maxn],ans[maxm],head[maxn],to[maxn<<1],nxt[maxn<<1],tot;
    int top[maxn],dep[maxn],siz[maxn],son[maxn],fa[maxn],id[maxn],tim;
    
    struct Query
    {
    	int op,x,y,z,lca,id;
    }p[maxm],q[maxm],q1[maxm],q2[maxm];
    
    inline int read()
    {
    	register int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return (f==1)?x:-x;
    }
    
    void print(int x)
    {
    	if(x<0){putchar('-');x=-x;}
    	if(x>9) print(x/10);
    	putchar(x%10+'0');
    }
    
    inline void add(int x,int y)
    {
    	for(;x<=n;x+=lowbit(x)) c[x]+=y;
    }
    
    inline int sum(int x)
    {
    	int ans=0;
    	for(;x;x-=lowbit(x)) ans+=c[x];
    	return ans;
    }
    
    inline void update(Query q,int z)
    {
    	add(id[q.x],z);add(id[q.y],z);add(id[q.lca],-z);
    	if(fa[q.lca]) add(id[fa[q.lca]],-z);  
    }
    
    inline int query(int x)
    {
    	return sum(id[x]+siz[x]-1)-sum(id[x]-1);
    }
    
    inline void addedge(int x,int y)
    {
    	to[++tot]=y;
    	nxt[tot]=head[x];
    	head[x]=tot;
    }
    
    void dfs1(int x,int f)
    {
    	siz[x]=1;fa[x]=f;dep[x]=dep[f]+1;
    	int maxson=-1;
    	for(int i=head[x],y;i;i=nxt[i])
    	{
    		y=to[i];
    		if(y==f) continue;
    		dfs1(y,x);siz[x]+=siz[y];
    		if(siz[y]>maxson) maxson=siz[y],son[x]=y;
    	}
    }
    
    void dfs2(int x,int topf)
    {
    	top[x]=topf;id[x]=++tim;
    	if(son[x]) dfs2(son[x],topf);
    	for(int i=head[x],y;i;i=nxt[i])
    	{
    		y=to[i];
    		if(y==fa[x]||y==son[x]) continue;
    		dfs2(y,y);
    	}
    }
    
    inline int LCA(int x,int y)
    {
    	while(top[x]!=top[y])
    	{
    		if(dep[top[x]]<dep[top[y]]) swap(x,y);
    		x=fa[top[x]];
    	}
    	if(dep[x]>dep[y]) swap(x,y);
    	return x;
    }
    
    void solve(int L,int R,int l,int r)
    {
    	if(L>R) return ;
    	if(l==r)
    	{
    		int cnt=0;
    		for(int i=L;i<=R;i++)
    		{
    			if(q[i].op==0) cnt++,update(q[i],1);
    			if(q[i].op==1) cnt--,update(p[q[i].id],-1);
    			if(q[i].op==2)
    			{
    				if(query(q[i].x)==cnt) ans[q[i].id]=-1;
    				else ans[q[i].id]=l;
    			}
    		}
    		for(int i=L;i<=R;i++)
    		{
    			if(q[i].op==0) update(q[i],-1);
    			if(q[i].op==1) update(p[q[i].id],1);
    		}
    		return ;
    	}
    	int mid=(l+r)>>1,cnt=0,cnt1=0,cnt2=0;
    	for(int i=L;i<=R;i++)
    	{
    		if(q[i].op==0)
    		{
    			if(q[i].z<=mid) q1[++cnt1]=q[i];
    			else cnt++,update(q[i],1),q2[++cnt2]=q[i];
    		}
    		if(q[i].op==1)
    		{
    			if(p[q[i].id].z<=mid) q1[++cnt1]=q[i];
    			else cnt--,update(p[q[i].id],-1),q2[++cnt2]=q[i];
    		}
    		if(q[i].op==2)
    		{
    			if(query(q[i].x)==cnt) q1[++cnt1]=q[i];
    			else q2[++cnt2]=q[i];
    		}
    	}
    	for(int i=L;i<=R;i++)
    	{
    		if(q[i].op==0&&q[i].z>mid) update(q[i],-1);
    		if(q[i].op==1&&p[q[i].id].z>mid) update(p[q[i].id],1);
    	}
    	for(int i=1;i<=cnt1;i++) q[L+i-1]=q1[i];
    	for(int i=1;i<=cnt2;i++) q[L+cnt1+i-1]=q2[i];
    	solve(L,L+cnt1-1,l,mid);solve(L+cnt1,L+cnt1+cnt2-1,mid+1,r);
    }
    
    int main()
    {
    	n=read(),m=read();
    	int x,y;
    	for(int i=1;i<n;i++)
    	{
    		x=read(),y=read();
    		addedge(x,y),addedge(y,x);
    	}
    	dfs1(1,0);dfs2(1,1);
    	for(int i=1;i<=m;i++)
    	{
    		q[i].op=read();
    		if(q[i].op==0) q[i].x=read(),q[i].y=read(),q[i].z=read(),q[i].lca=LCA(q[i].x,q[i].y);
    		if(q[i].op==1) q[i].id=read();
    		if(q[i].op==2) q[i].x=read(),q[i].id=++qn;
    		p[i]=q[i];
    	}
    	solve(1,m,1,1e9);
    	for(int i=1;i<=qn;i++) print(ans[i]),putchar('
    ');
    	return 0;
    }
    

    附上一个 (LCT) 版被卡常的版本:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=100000+10;
    const int maxm=200000+10;
    int n,m,qn,id[maxm],ans[maxm],head[maxn],to[maxn<<1],nxt[maxn<<1],tot;
    
    struct Query
    {
    	int op,x,y,z,id;
    }p[maxm],q[maxm],q1[maxm],q2[maxm];
    
    inline int read()
    {
    	register int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return (f==1)?x:-x;
    }
    
    void print(int x)
    {
    	if(x<0){putchar('-');x=-x;}
    	if(x>9) print(x/10);
    	putchar(x%10+'0');
    }
    
    namespace LCT
    {
    	int ch[maxn][2],fa[maxn],val[maxn],tag[maxn],sta[maxn],top;bool rev[maxn];
    	inline void reverse(int x)
    	{
    		rev[x]^=1;
    		swap(ch[x][0],ch[x][1]);
    	}
    	inline void pushtag(int x,int y){val[x]+=y;tag[x]+=y;}
    	inline void pushdown(int x)
    	{
    		if(tag[x])
    		{
    			if(ch[x][0]) pushtag(ch[x][0],tag[x]);
    			if(ch[x][1]) pushtag(ch[x][1],tag[x]);
    			tag[x]=0;
    		}
    		if(rev[x])
    		{
    			if(ch[x][0]) reverse(ch[x][0]);
    			if(ch[x][1]) reverse(ch[x][1]);
    			rev[x]=0;
    		}
    	}
    	inline bool nrt(int x){return ch[fa[x]][0]==x||ch[fa[x]][1]==x;}
    	inline void rotate(int x)
    	{
    		int y=fa[x],z=fa[y],k=(ch[y][1]==x),u=ch[x][k^1];
    		if(nrt(y)) ch[z][ch[z][1]==y]=x;
    		ch[y][k]=u;ch[x][k^1]=y;
    		if(u) fa[u]=y;fa[y]=x;fa[x]=z;
    	}
    	inline void splay(int x)
    	{
    		int y,z;top=0;
    		for(y=x;nrt(y);y=fa[y]) sta[++top]=y;
    		pushdown(y);
    		while(top) pushdown(sta[top--]);
    		while(nrt(x))
    		{
    			y=fa[x],z=fa[y];
    			if(nrt(y)) rotate((ch[y][1]==x)^(ch[z][1]==y)?x:y);
    			rotate(x);
    		}
    	}
    	inline void access(int x)
    	{
    		for(int y=0;x;y=x,x=fa[x])
    			splay(x),ch[x][1]=y;
    	}
    	inline void makeroot(int x)
    	{
    		access(x),splay(x),reverse(x);
    	}
    	inline int findroot(int x)
    	{
    		access(x),splay(x);
    		for(;ch[x][0];x=ch[x][0]) pushdown(x);
    		return x;
    	}
    	inline void split(int x,int y)
    	{
    		makeroot(x),access(y),splay(y);
    	}
    	inline void link(int x,int y){fa[x]=y;}
    }
    
    inline void addedge(int x,int y)
    {
    	to[++tot]=y;
    	nxt[tot]=head[x];
    	head[x]=tot;
    }
    
    void dfs(int x,int f)
    {
    	if(f) LCT::link(x,f);
    	for(int i=head[x],y;i;i=nxt[i])
    		if((y=to[i])!=f) dfs(y,x);
    }
    
    inline void calc(int x,int y,int z)
    {
    	LCT::split(x,y);LCT::pushtag(y,z);
    }
    
    void solve(int L,int R,int l,int r)
    {
    	if(L>R) return ;
    //	printf("solve(%d, %d, %d, %d)
    ",L,R,l,r);
    //	for(int i=L;i<=R;i++)
    //	{
    //		if(q[i].op==0) printf("%d %d %d %d %d
    ",q[i].op,q[i].x,q[i].y,q[i].z);
    //		if(q[i].op==1) printf("%d %d
    ",q[i].op,q[i].id);
    //		if(q[i].op==2) printf("%d %d
    ",q[i].op,q[i].x);
    //	}
    //	printf("
    ");
    	if(l==r)
    	{
    		int cnt=0;
    		for(int i=L;i<=R;i++)
    		{
    			if(q[i].op==0) cnt++,calc(q[i].x,q[i].y,1);
    			if(q[i].op==1) cnt--,calc(p[q[i].id].x,p[q[i].id].y,-1);
    			if(q[i].op==2)
    			{
    				LCT::makeroot(q[i].x);
    				if(LCT::val[q[i].x]==cnt) ans[q[i].id]=-1;
    				else ans[q[i].id]=l;
    			}
    		}
    		for(int i=L;i<=R;i++)
    		{
    			if(q[i].op==0) calc(q[i].x,q[i].y,-1);
    			if(q[i].op==1) calc(p[q[i].id].x,p[q[i].id].y,1);
    		}
    		return ;
    	}
    	int mid=(l+r)>>1,cnt=0,cnt1=0,cnt2=0;
    	for(int i=L;i<=R;i++)
    	{
    		if(q[i].op==0)
    		{
    			if(q[i].z<=mid) q1[++cnt1]=q[i];
    			else cnt++,calc(q[i].x,q[i].y,1),q2[++cnt2]=q[i];
    		}
    		if(q[i].op==1)
    		{
    			if(p[q[i].id].z<=mid) q1[++cnt1]=q[i];
    			else cnt--,calc(p[q[i].id].x,p[q[i].id].y,-1),q2[++cnt2]=q[i];
    		}
    		if(q[i].op==2)
    		{
    			LCT::makeroot(q[i].x);
    			if(LCT::val[q[i].x]==cnt) q1[++cnt1]=q[i];
    			else q2[++cnt2]=q[i];
    		}
    	}
    	for(int i=L;i<=R;i++)
    	{
    		if(q[i].op==0&&q[i].z>mid) calc(q[i].x,q[i].y,-1);
    		if(q[i].op==1&&p[q[i].id].z>mid) calc(p[q[i].id].x,p[q[i].id].y,1);
    	}
    	for(int i=1;i<=cnt1;i++) q[L+i-1]=q1[i];
    	for(int i=1;i<=cnt2;i++) q[L+cnt1+i-1]=q2[i];
    	solve(L,L+cnt1-1,l,mid);solve(L+cnt1,L+cnt1+cnt2-1,mid+1,r);
    }
    
    int main()
    {
    	n=read(),m=read();
    	int x,y;
    	for(int i=1;i<n;i++)
    	{
    		x=read(),y=read();
    		addedge(x,y),addedge(y,x);
    	}
    	dfs(1,0);
    	for(int i=1;i<=m;i++)
    	{
    		q[i].op=read();
    		if(q[i].op==0) q[i].x=read(),q[i].y=read(),q[i].z=read();
    		if(q[i].op==1) q[i].id=read();
    		if(q[i].op==2) q[i].x=read(),q[i].id=++qn;
    		p[i]=q[i];
    	}
    	solve(1,m,1,1e9);
    	for(int i=1;i<=qn;i++) print(ans[i]),putchar('
    ');
    	return 0;
    }
    

    「HNOI2016」序列

    只会莫队,不适轻喷。。。

    我们对于端点的移动计算贡献。

    比如从 ([l,r])([l,r+1]) 时我们考虑左端点在 ([l,r[) 右端点在 (r+1) 的答案。

    首先找到 ([l,r]) 最小值的位置 (k),左端点在 ([l,k]) 的贡献为 ((k-l+1) imes a_k)

    那么现在维护一个 (lsum,rsum),表示左端点/右端点固定时的答案,此时左端点在 ([k+1,r]) 的贡献为 (rsum[r+1]-rsum[k])

    左端点的移动也是类似的,时间复杂度 (O(nsqrt{n}))

    (Code Below:)

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=100000+10;
    int n,m,a[maxn],lg[maxn],Min[maxn][18],sta[maxn],top,blo,L,R;
    ll lsum[maxn],rsum[maxn],ans[maxn],now;
    
    struct Query{
    	int l,r,id;
    }q[maxn];
    
    inline bool cmp(const Query &a,const Query &b){
    	if((a.l-1)/blo!=(b.l-1)/blo)
    		return (a.l-1)/blo<(b.l-1)/blo;
    	return a.r<b.r;
    }
    
    inline int read(){
    	register int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return (f==1)?x:-x;
    }
    
    inline int query(int l,int r){
    	int k=lg[r-l+1];
    	return a[Min[l][k]]<a[Min[r-(1<<k)+1][k]]?Min[l][k]:Min[r-(1<<k)+1][k];
    }
    
    inline void addl(int x){
    	int k=query(L,R);
    	now+=lsum[L]-lsum[k]+1ll*(R-k+1)*a[k];
    }
    inline void dell(int x){
    	int k=query(L,R);
    	now-=lsum[L]-lsum[k]+1ll*(R-k+1)*a[k];
    }
    inline void addr(int x){
    	int k=query(L,R);
    	now+=rsum[R]-rsum[k]+1ll*(k-L+1)*a[k];
    }
    inline void delr(int x){
    	int k=query(L,R);
    	now-=rsum[R]-rsum[k]+1ll*(k-L+1)*a[k];
    }
    
    int main()
    {
    	n=read(),m=read();blo=sqrt(n)+1;
    	for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
    	for(int i=1;i<=n;i++) a[i]=read(),Min[i][0]=i;
    	for(int j=1;j<18;j++)
    		for(int i=1;i+(1<<j)-1<=n;i++) Min[i][j]=a[Min[i][j-1]]<a[Min[i+(1<<(j-1))][j-1]]?Min[i][j-1]:Min[i+(1<<(j-1))][j-1];
    	for(int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),q[i].id=i;
    	for(int i=1;i<=n;i++){
    		while(top&&a[sta[top]]>a[i]) top--;
    		rsum[i]=rsum[sta[top]]+1ll*(i-sta[top])*a[i];sta[++top]=i;
    	}
    	for(int i=n;i>=1;i--){
    		while(top&&a[sta[top]]>=a[i]) top--;
    		lsum[i]=lsum[sta[top]]+1ll*(sta[top]-i)*a[i];sta[++top]=i;
    	}
    	sort(q+1,q+m+1,cmp);
    	L=1,R=0;
    	for(int i=1;i<=m;i++){
    		while(R<q[i].r) R++,addr(R);
    		while(R>q[i].r) delr(R),R--;
    		while(L<q[i].l) dell(L),L++;
    		while(L>q[i].l) L--,addl(L);
    		ans[q[i].id]=now;
    	}
    	for(int i=1;i<=m;i++) printf("%lld
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    header头参数 确定该文件类型
    phpexcel 使用说明
    杂七杂八 各种小知识
    php 后知后觉
    限制SSH登录失败次数
    DES和AES密码之间的区别 & 对称加密算法DES、3DES和AES 原理总结
    加密算法(DES,AES,RSA,MD5,SHA1,Base64)比较和项目应用
    加密算法学习总结---DES-CBC加密算法 & 分组加密的四种模式
    Linux下进程间通信方式——共享内存
    fork()+pipe() --&gt; 父子进程间通过管道通信 Linux系统编程pipe()
  • 原文地址:https://www.cnblogs.com/owencodeisking/p/10617048.html
Copyright © 2011-2022 走看看