• 【BZOJ2002】 [Hnoi2010]Bounce 弹飞绵羊


    BZOJ2002 [Hnoi2010]Bounce 弹飞绵羊


    Solution

    很早以前写的一道分块题,最近在搞LCT,又做了一遍.

    1.LCT做法

    看到这种动态修改,想下LCT怎么维护.

    修改操作就是(Cut(x,k[x]))然后再(Link(x,k[x]'))

    剩下的只有询问了.

    我们如果把弹出设为一个新节点(n+1),那么显然就是直接:

    (makeroot(x)),(access(n+1)),(splay(n+1)).

    最后答案就是(siz[n+1].)

    2.分块做法

    我们如果把编号分块,那么显然每一次修改就维护一下弹出的到了哪个块,然后随便搞一下就可以了.

    代码实现

    LCT

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<map>
    #include<iostream>
    using namespace std;
    #define ll long long
    #define re register
    #define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
    inline int gi()
    {
    	int f=1,sum=0;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return f*sum;
    }
    const int N=300010;
    int K[N],n;
    struct node
    {
    	int ff,ch[2],siz,rev;
    }t[N];
    int sta[N],top;
    void pushup(int x)
    {
    	t[x].siz=t[t[x].ch[0]].siz+t[t[x].ch[1]].siz+1;
    }
    void reverse(int x)
    {
    	swap(t[x].ch[0],t[x].ch[1]);
    	t[x].rev^=1;
    }
    void pushdown(int x)
    {
    	if(!t[x].rev)return;
    	if(t[x].ch[0])reverse(t[x].ch[0]);
    	if(t[x].ch[1])reverse(t[x].ch[1]);
    	t[x].rev^=1;
    }
    bool isroot(int x)
    {
    	return (t[t[x].ff].ch[0]!=x) && (t[t[x].ff].ch[1]!=x);
    }
    void rotate(int x)
    {
    	int y=t[x].ff,z=t[y].ff;
    	int k=t[y].ch[1]==x;
    	if(!isroot(y))t[z].ch[t[z].ch[1]==y]=x;//只能在这一棵Splay里面Rotate
    	t[x].ff=z;
    	t[y].ch[k]=t[x].ch[k^1];
    	t[t[x].ch[k^1]].ff=y;
    	t[x].ch[k^1]=y;t[y].ff=x;
    	pushup(y);pushup(x);
    }
    void splay(int x)
    {
    	sta[++top]=x;
    	for(int i=x;!isroot(i);i=t[i].ff)sta[++top]=t[i].ff;
    	while(top)pushdown(sta[top--]);
    	while(!isroot(x))
    	{
    		int y=t[x].ff,z=t[y].ff;
    		if(!isroot(y))//Splay是旋转到当前这棵Splay的根,这个道理就和上面的rotate是一样的.
    			(t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
    		rotate(x);
    	}
    	pushup(x);
    }
    void access(int x)
    {
    	for(int y=0;x;y=x,x=t[x].ff)
    	{
    		splay(x);
    		t[x].ch[1]=y;
    		pushup(x);
    	}
    }
    void makeroot(int x)
    {
    	access(x);splay(x);
    	reverse(x);
    }
    int findroot(int x)
    {
    	access(x);splay(x);
    	while(t[x].ch[0])x=t[x].ch[0];
    	return x;
    }
    void split(int x,int y)
    {
    	makeroot(x);
    	access(y);
    	splay(y);
    }
    void link(int x,int y)
    {
    	makeroot(x);
    	t[x].ff=y;
    }
    void cut(int x,int y)
    {
    	split(x,y);
    	t[y].ch[0]=t[x].ff=0;
    }
    int judge(int x)
    {
    	return x>n?n+1:x;
    }
    int main()
    {
    	n=gi();
    	for(int i=1;i<=n;i++)
    		t[i].siz=1;
    	for(int i=1;i<=n;i++)
    		link(i,judge(i+(K[i]=gi())));
    	int Q=gi();
    	while(Q--)
    	{
    		int opt=gi(),u=gi();u++;
    		if(opt==1)
    		{
    			makeroot(u);access(n+1);splay(n+1);
    			printf("%d
    ",t[n+1].siz-1);
    		}
    		if(opt==2)
    		{
    			int tmp=K[u];
    			K[u]=gi();
    			cut(u,judge(u+tmp));
    			link(u,judge(u+K[u]));
    		}
    	}
    	return 0;
    }
    

    分块

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<queue>
    #include<iostream>
    using namespace std;
    inline int gi(){
        int sum=0,f=1;char ch=getchar();
        while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
        return f*sum;
    }
    const int N=400010;
    int bl[N],nxt[N],sum[N],a[N];
    int n,B,m;
    void ask(int l,int r){
        for(int i=r;i>=l;i--)
            if(i+a[i]>min(n,bl[i]*B))sum[i]=1,nxt[i]=i+a[i];
            else sum[i]=sum[i+a[i]]+1,nxt[i]=nxt[i+a[i]];
    }
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("in.in","r",stdin);
        freopen("out.out","w",stdout);
    #endif
        n=gi();B=sqrt(n);
        for(int i=1;i<=n;i++)a[i]=gi();
        for(int i=1;i<=n;i++)
            bl[i]=(i-1)/B+1;
        ask(1,n);
        m=gi();int all=bl[n];
        while(m--){
            int opt=gi(),x=gi();x++;
            if(opt==1){
                int ans=sum[x],now=nxt[x],i=bl[x];
                while(now<=n && i<=all){ans+=sum[now];now=nxt[now];i++;}
                printf("%d
    ",ans);
            }
            else{
                int k=gi();
                a[x]=k;
                ask((bl[x]-1)*B+1,min(bl[x]*B,n));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    内部共享上网
    Harbor部署
    一、Gitlab安装
    Dockerfile
    DockerCompose
    二、Git
    nginx域名代理
    三、jenkins持续集成工具安装
    chrome对于“submit”关键字的保留
    insightface 提取人脸特征(超简洁)
  • 原文地址:https://www.cnblogs.com/mleautomaton/p/10340466.html
Copyright © 2020-2023  润新知