zoukankan      html  css  js  c++  java
  • 【刷题】BZOJ 2157 旅游

    Description

    Ray 乐忠于旅游,这次他来到了T 城。T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接。为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路径。换句话说, T 城中只有N − 1 座桥。Ray 发现,有些桥上可以看到美丽的景色,让人心情愉悦,但有些桥狭窄泥泞,令人烦躁。于是,他给每座桥定义一个愉悦度w,也就是说,Ray 经过这座桥会增加w 的愉悦度,这或许是正的也可能是负的。有时,Ray 看待同一座桥的心情也会发生改变。现在,Ray 想让你帮他计算从u 景点到v 景点能获得的总愉悦度。有时,他还想知道某段路上最美丽的桥所提供的最大愉悦度,或是某段路上最糟糕的一座桥提供的最低愉悦度。

    Input

    输入的第一行包含一个整数N,表示T 城中的景点个数。景点编号为 0...N − 1。接下来N − 1 行,每行三个整数u、v 和w,表示有一条u 到v,使 Ray 愉悦度增加w 的桥。桥的编号为1...N − 1。|w| <= 1000。输入的第N + 1 行包含一个整数M,表示Ray 的操作数目。接下来有M 行,每行描述了一个操作,操作有如下五种形式: C i w,表示Ray 对于经过第i 座桥的愉悦度变成了w。 N u v,表示Ray 对于经过景点u 到v 的路径上的每一座桥的愉悦度都变成原来的相反数。 SUM u v,表示询问从景点u 到v 所获得的总愉悦度。 MAX u v,表示询问从景点u 到v 的路径上的所有桥中某一座桥所提供的最大愉悦度。 MIN u v,表示询问从景点u 到v 的路径上的所有桥中某一座桥所提供的最小愉悦度。测试数据保证,任意时刻,Ray 对于经过每一座桥的愉悦度的绝对值小于等于1000。

    Output

    对于每一个询问(操作S、MAX 和MIN),输出答案。

    Sample Input

    3

    0 1 1

    1 2 2

    8

    SUM 0 2

    MAX 0 2

    N 0 1

    SUM 0 2

    MIN 0 2

    C 1 3

    SUM 0 2

    MAX 0 2

    Sample Output

    3

    2

    1

    -1

    5

    3

    HINT

    一共有10 个数据,对于第i (1 <= i <= 10) 个数据, N = M = i * 2000。

    Solution

    LCT

    这个LCT还是比较裸的

    维护三个,Sm,Mn,Mx

    对于取相反数,类似于反转标记,而取反的pushdown就是先把所有维护的东西取反,然后发现取反后,以前最大的现在变成最小的了,以前最小的现在变成最大的了,所以直接swap就好了

    #include<bits/stdc++.h>
    #define ll long long
    #define db double
    #define ld long double
    const int MAXN=100000+10,MAXM=100000+10,inf=0x3f3f3f3f;
    int n,m;
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    #define lc(x) ch[(x)][0]
    #define rc(x) ch[(x)][1]
    struct LCT{
    	int ch[MAXN+MAXM][2],fa[MAXN+MAXM],rev[MAXN+MAXM],Mn[MAXN+MAXM],Mx[MAXN+MAXM],Sm[MAXN+MAXM],stack[MAXN+MAXM],cnt,una[MAXN+MAXM],val[MAXN+MAXM];
    	inline void init()
    	{
    		memset(ch,0,sizeof(ch));
    		memset(fa,0,sizeof(fa));
    		memset(rev,0,sizeof(rev));
    		memset(una,0,sizeof(una));
    		memset(Mx,-inf,sizeof(Mx));
    		memset(Mn,inf,sizeof(Mn));
    		memset(Sm,0,sizeof(Sm));
    		memset(val,0,sizeof(val));
    	}
    	inline bool nroot(int x)
    	{
    		return lc(fa[x])==x||rc(fa[x])==x;
    	}
    	inline void reverse(int x)
    	{
    		std::swap(lc(x),rc(x));
    		rev[x]^=1;
    	}
    	inline void unary(int x)
    	{
    		val[x]=-val[x];Sm[x]=-Sm[x];Mx[x]=-Mx[x];Mn[x]=-Mn[x];
    		std::swap(Mx[x],Mn[x]);
    		una[x]^=1;
    	}
    	inline void pushup(int x)
    	{
    		Sm[x]=Sm[lc(x)]+Sm[rc(x)]+val[x];
    		Mx[x]=max(Mx[lc(x)],Mx[rc(x)]);
    		Mn[x]=min(Mn[lc(x)],Mn[rc(x)]);
    		if(x>n)chkmax(Mx[x],val[x]);
    		if(x>n)chkmin(Mn[x],val[x]);
    	}
    	inline void pushdown(int x)
    	{
    		if(una[x])
    		{
    			if(lc(x))unary(lc(x));
    			if(rc(x))unary(rc(x));
    			una[x]=0;
    		}
    		if(rev[x])
    		{
    			if(lc(x))reverse(lc(x));
    			if(rc(x))reverse(rc(x));
    			rev[x]=0;
    		}
    	}
    	inline void rotate(int x)
    	{
    		int f=fa[x],p=fa[f],c=(rc(f)==x);
    		if(nroot(f))ch[p][rc(p)==f]=x;
    		fa[ch[f][c]=ch[x][c^1]]=f;
    		fa[ch[x][c^1]=f]=x;
    		fa[x]=p;
    		pushup(f);
    		pushup(x);
    	}
    	inline void splay(int x)
    	{
    		cnt=0;
    		stack[++cnt]=x;
    		for(register int i=x;nroot(i);i=fa[i])stack[++cnt]=fa[i];
    		while(cnt)pushdown(stack[cnt--]);
    		for(register int y=fa[x];nroot(x);rotate(x),y=fa[x])
    			if(nroot(y))rotate((lc(y)==x)==(lc(fa[y])==y)?y:x);
    		pushup(x);
    	}
    	inline void access(int x)
    	{
    		for(register int y=0;x;x=fa[y=x])splay(x),rc(x)=y,pushup(x);
    	}
    	inline void makeroot(int x)
    	{
    		access(x);splay(x);reverse(x);
    	}
    	inline void split(int x,int y)
    	{
    		makeroot(x);access(y);splay(y);
    	}
    	inline void link(int x,int y)
    	{
    		makeroot(x);fa[x]=y;
    	}
    };
    LCT T;
    #undef lc
    #undef rc
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char c='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(c!='')putchar(c);
    }
    int main()
    {
    	read(n);
    	T.init();
    	for(register int i=1;i<n;++i)
    	{
    		int u,v,w,sn=n+i;
    		read(u);read(v);read(w);
    		u++;v++;
    		T.val[sn]=w;
    		T.link(sn,u);T.link(sn,v);
    	}
    	read(m);
    	while(m--)
    	{
    		char opt[5];
    		scanf("%s",opt);
    		if(!strcmp(opt,"SUM"))
    		{
    			int u,v;
    			read(u);read(v);
    			u++;v++;
    			T.split(u,v);
    			write(T.Sm[v],'
    ');
    		}
    		if(!strcmp(opt,"MAX"))
    		{
    			int u,v;
    			read(u);read(v);
    			u++;v++;
    			T.split(u,v);
    			write(T.Mx[v],'
    ');
    		}
    		if(!strcmp(opt,"MIN"))
    		{
    			int u,v;
    			read(u);read(v);
    			u++;v++;
    			T.split(u,v);
    			write(T.Mn[v],'
    ');
    		}
    		if(!strcmp(opt,"C"))
    		{
    			int id,w;
    			read(id);read(w);
    			int sn=id+n;
    			T.access(sn);T.splay(sn);
    			T.val[sn]=w;
    			T.pushup(sn);
    		}
    		if(!strcmp(opt,"N"))
    		{
    			int u,v;
    			read(u);read(v);
    			u++;v++;
    			T.split(u,v);T.unary(v);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    java:数组操作工具类 java.util.Arrays包 主要方法详解
    java:接口特性 接口与抽象类/普通类的区别
    mybatis教程:入门>>精通>>实战
    Java :内部类基础详解
    Java swing: 实现ActionListener监听器的三种途径
    Java:final、static关键字 详解+两者结合使用
    Java:双括号初始化 /匿名内部类初始化法
    Java:静态内部类的使用目的、使用限制、与非静态内部类的对比
    域名解析>>"记录类型" 说明
    Java:接口继承接口 (多继承机制)
  • 原文地址:https://www.cnblogs.com/hongyj/p/8710947.html
Copyright © 2011-2022 走看看