zoukankan      html  css  js  c++  java
  • 【XSY2528】道路建设 LCT 可持久化线段树

    题目描述

      给你一个(n)个点(m)条边图,(q)个询问,每次问你边权在([l,r])之间的边组成的最小生成树(森林)的边权和。强制在线。

      (n,m,qleq 100000)

    题解

      考虑离线做法。从大到小加边,用LCT维护当前的最小生成树。维护一棵线段树,第(i)个位置表示当前的最小生成树中边权为(i)的边的权值和。当一条边被加入时就在对应位置加上边权,删掉时就减掉边权。假设已经处理了边权(geq i)的所有边,那么对于所有(l=i)的询问的答案就是线段树中([1,r])的数和(等价于([l,r]),因为([1,l-1])都是空的)。

      把这棵线段树变成可持久化线段树就可以在线处理询问了。

      我也不知道为什么边权范围是([1,10000])

      时间复杂度:(O((m+q)log n))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #include<utility>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    namespace lct
    {
    	int f[200010];
    	int a[200010][2];
    	pii s[200010];
    	pii v[200010];
    	int rev[200010];
    	void reverse(int x)
    	{
    		rev[x]^=1;
    		swap(a[x][0],a[x][1]);
    	}
    	void push(int x)
    	{
    		if(rev[x])
    		{
    			if(a[x][0])
    				reverse(a[x][0]);
    			if(a[x][1])
    				reverse(a[x][1]);
    			rev[x]=0;
    		}
    	}
    	void mt(int x)
    	{
    		s[x]=v[x];
    		if(a[x][0])
    			s[x]=max(s[x],s[a[x][0]]);
    		if(a[x][1])
    			s[x]=max(s[x],s[a[x][1]]);
    	}
    	int root(int x)
    	{
    		return !f[x]||(a[f[x]][0]!=x&&a[f[x]][1]!=x);
    	}
    	void rotate(int x)
    	{
    		if(root(x))
    			return;
    		int p=f[x];
    		int q=f[p];
    		int ps=(x==a[p][1]);
    		int qs=(p==a[q][1]);
    		int ch=a[x][ps^1];
    		if(!root(p))
    			a[q][qs]=x;
    		a[x][ps^1]=p;
    		a[p][ps]=ch;
    		if(ch)
    			f[ch]=p;
    		f[p]=x;
    		f[x]=q;
    		mt(p);
    		mt(x);
    	}
    	void pushdown(int x)
    	{
    		if(!root(x))
    			pushdown(f[x]);
    		push(x);
    	}
    	void splay(int x)
    	{
    		pushdown(x);
    		while(!root(x))
    		{
    			int p=f[x];
    			if(!root(p))
    			{
    				int q=f[p];
    				if((x==a[p][1])^(p==a[q][1]))
    					rotate(x);
    				else
    					rotate(p);
    			}
    			rotate(x);
    		}
    	}
    	void access(int x)
    	{
    		int y=x,t=0;
    		while(x)
    		{
    			splay(x);
    			a[x][1]=t;
    			mt(x);
    			t=x;
    			x=f[x];
    		}
    		splay(y);
    	}
    	void change(int x)
    	{
    		access(x);
    		reverse(x);
    	}
    	void link(int x,int y)
    	{
    		change(x);
    		f[x]=y;
    	}
    	void cut(int x,int y)
    	{
    		change(x);
    		access(y);
    		f[a[y][0]]=0;
    		a[y][0]=0;
    	}
    	pii query(int x,int y)
    	{
    		change(x);
    		access(y);
    		return s[y];
    	}
    	int findroot(int x)
    	{
    		access(x);
    		while(a[x][0])
    			x=a[x][0];
    		splay(x);
    		return x;
    	}
    }
    namespace seg
    {
    	int n=0;
    	int ls[5000010];
    	int rs[5000010];
    	int s[5000010];
    	int rt[100010];
    	int change(int p1,int x,int v,int l,int r)
    	{
    		int p=++n;
    		ls[p]=ls[p1];
    		rs[p]=rs[p1];
    		s[p]=s[p1]+v;
    		if(l==r)
    			return p;
    		int mid=(l+r)>>1;
    		if(x<=mid)
    			ls[p]=change(ls[p1],x,v,l,mid);
    		if(x>mid)
    			rs[p]=change(rs[p1],x,v,mid+1,r);
    		return p;
    	}
    	int query(int p,int l,int r,int L,int R)
    	{
    		if(l<=L&&r>=R)
    			return s[p];
    		int mid=(L+R)>>1;
    		int res=0;
    		if(l<=mid)
    			res+=query(ls[p],l,r,L,mid);
    		if(r>mid)
    			res+=query(rs[p],l,r,mid+1,R);
    		return res;
    	}
    }
    struct edge
    {
    	int x,y,d;
    };
    int cmp(edge a,edge b)
    {
    	return a.d<b.d;
    }
    edge a[100010];
    int main()
    {
    	freopen("c.in","r",stdin);
    	freopen("c.out","w",stdout);
    	int n,m,on;
    	scanf("%d%d%d",&n,&m,&on);
    	int i;
    	for(i=1;i<=m;i++)
    		scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].d);
    	sort(a+1,a+m+1,cmp);
    	int j=m;
    	seg::rt[n+1]=0;
    	for(i=1;i<=n;i++)
    		lct::v[i]=pii(0,0);
    	for(i=10000;i>=1;i--)
    	{
    		seg::rt[i]=seg::rt[i+1];
    		while(j>=1&&a[j].d==i)
    		{
    			int rx=lct::findroot(a[j].x);
    			int ry=lct::findroot(a[j].y);
    			if(rx==ry)
    			{
    				pii s=lct::query(a[j].x,a[j].y);
    				if(s.first>a[j].d)
    				{
    					lct::cut(a[s.second].x,s.second+n);
    					lct::cut(a[s.second].y,s.second+n);
    					lct::v[j+n]=pii(a[j].d,j);
    					lct::link(a[j].x,j+n);
    					lct::link(a[j].y,j+n);
    					seg::rt[i]=seg::change(seg::rt[i],s.first,-s.first,1,10000);
    					seg::rt[i]=seg::change(seg::rt[i],a[j].d,a[j].d,1,10000);
    				}
    			}
    			else
    			{
    				lct::v[j+n]=pii(a[j].d,j);
    				lct::link(a[j].x,j+n);
    				lct::link(a[j].y,j+n);
    				seg::rt[i]=seg::change(seg::rt[i],a[j].d,a[j].d,1,10000);
    			}
    			j--;
    		}
    	}
    	int q;
    	scanf("%d",&q);
    	int l,h,last=0;
    	for(i=1;i<=q;i++)
    	{
    		scanf("%d%d",&l,&h);
    		l-=on*last;
    		h-=on*last;
    		last=seg::query(seg::rt[l],1,h,1,10000);
    		printf("%d
    ",last);
    	}
    	return 0;
    }
    
  • 相关阅读:
    由一段代码说开去——set
    由一段代码说开去——list
    day 11
    day 16
    day 10
    day 13
    day 9
    day 18
    day 12
    day 14
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8513137.html
Copyright © 2011-2022 走看看