• [JZOJ6257] 【省选模拟8.9】修路


    题目

    题目大意

    有一堆点,每个点都有其权值(c_i)
    每次插入边((u,v))(u)(1)连通,(v)(1)不连通。最后保证形成一棵树。
    每次插入的时候询问(1)(u)的路径上逆序对的个数。然后将(1)(u)的路径上的所有节点的权值设为(c_v).


    思考历程

    一看就知道是什么数据结构题了……
    然而刚了很久都不知道怎么做……
    于是就直接打暴力。暴力跳(fa),用树状数组计算逆序对的个数。
    后来还有点时间,于是看准了(c_ileq 2)的数据。
    于是打了个树链剖分加线段树来维护。线段树上每个区间维护的是个大小为(3)的桶和答案,区间合并的时候就是左右两边的答案加上左边权值大于右边的个数。
    打完了之后急着去吃饭,完全没有调过……
    后来发现这个树链剖分没有分……倒是覆盖了我的暴力……原来暴力是可以吃掉(c_ileq 2)的数据的……


    正解

    看到正解的时候我也震惊了……
    请用脑子模拟一下操作的画面。
    然后试着跟(LCT)建立联系。

    于是我们就发现这个操作过程与(LCT)神似!
    每个(splay)维护权值相同的一条链,修改的时候相当于(access)上去……
    将它到祖先的路径全部变成同一个权值。
    我们也知道(LCT)的时间复杂度是均摊(lg n)的。虽然不会证明。
    那么我们可以理解成出现过的颜色相同的段数是(O(nlg n))级别的。
    询问的时候用树状数组来维护。模拟(access)的过程就可以了。

    于是这题就非常轻松地AC了。而且由于这题完全不需要(mroot)操作,所以也不用翻转……
    (LCT)短得跟树链剖分差不多……


    代码

    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 100010
    int n;
    int c[N],maxc;
    int *p[N];
    inline bool cmpp(int *x,int *y){
    	return *x<*y;
    }
    int t[N];
    #define lowbit(x) ((x)&(-(x)))
    inline void add(int x,int c){
    	for (;x<=maxc;x+=lowbit(x))
    		t[x]+=c;
    }
    inline int query(int x){
    	int res=0;
    	for (;x;x-=lowbit(x))
    		res+=t[x];
    	return res;
    }
    inline void clear(int x){
    	for (;x<=maxc && t[x];x+=lowbit(x))
    		t[x]=0;
    }
    struct Node{
    	Node *fa,*c[2];
    	int is_root;
    	int siz;
    	inline void update(){siz=c[0]->siz+c[1]->siz+1;}
    	inline bool getson(){return fa->c[0]!=this;}
    	inline void rotate(){
    		Node *y=fa,*z=y->fa;
    		if (y->is_root){
    			is_root=y->is_root;
    			y->is_root=0;
    		}
    		else
    			z->c[y->getson()]=this;
    		int k=getson();
    		fa=z;
    		y->c[k]=c[k^1];
    		c[k^1]->fa=y;
    		c[k^1]=y;
    		y->fa=this;
    		siz=y->siz,y->update();
    	}
    	inline void splay(){
    		while (!is_root){
    			if (!fa->is_root){
    				if (getson()!=fa->getson())
    					rotate();
    				else
    					fa->rotate();
    			}
    			rotate();
    		}
    	}
    } d[N],*null;
    int main(){
    	freopen("road.in","r",stdin);
    	freopen("road.out","w",stdout);
    	scanf("%d",&n);
    	for (int i=1;i<=n;++i)
    		scanf("%d",&c[i]),p[i]=&c[i];
    	sort(p+1,p+n+1,cmpp);
    	for (int i=1,last=-1;i<=n;++i){
    		if (*p[i]!=last){
    			maxc++;
    			last=*p[i];
    		}
    		*p[i]=maxc;
    	}
    	null=d;
    	*null={null,null,null,0,0};
    	for (int i=1;i<=n;++i)
    		d[i]={null,null,null,c[i],1};
    	for (int i=1;i<n;++i){
    		int u,v;
    		scanf("%d%d",&u,&v);
    		Node *x,*y;
    		long long ans=0;
    		for (x=&d[u];x!=null;x=x->fa){
    			x->splay();
    			ans+=(long long)query(x->is_root-1)*(x->c[0]->siz+1);
    			add(x->is_root,x->c[0]->siz+1);
    		}
    		printf("%lld
    ",ans);
    		d[v].fa=&d[u];
    		for (x=&d[v],y=null;x!=null;y=x,x=x->fa){
    			x->splay();
    			clear(x->is_root);
    			x->c[1]->is_root=x->is_root;
    			x->c[1]=y;
    			y->is_root=0;
    			x->update();
    		}
    		y->is_root=c[v];
    	}
    	return 0;
    }
    

    思考历程

    在分析复杂度的时候,可以试着结合自己学过的数据结构……

  • 相关阅读:
    Row size too large. The maximum row size for the used table type 解决
    pandas Series介绍
    Scala核心编程_第08章 面向对象编程(中高级部分)
    mysql增删改字段,重命名替换字段
    python报错ValueError: cannot reindex from a duplicate axis
    pandas DataFrame 数据筛选
    Scala核心编程_第07章 面向对象编程(中级部分)
    Scala核心编程_第06章 面向对象编程(基础部分)
    《The Rise and Fall of Scala》scala兴衰读后感
    信贷业务(Ali)
  • 原文地址:https://www.cnblogs.com/jz-597/p/11329667.html
Copyright © 2020-2023  润新知