洛谷P4312 [COCI 2009] OTOCI

题目描述

给出n个结点以及每个点初始时对应的权值wi。起始时点与点之间没有连边。有3类操作:

  1. bridge A B:询问结点A与结点B是否连通。如果是则输出“no”。否则输出“yes”,并且在结点A和结点B之间连一条无向边。
  2. penguins A X:将结点A对应的权值wA修改为X。
  3. excursion A B:如果结点A和结点B不连通,则输出“impossible”。否则输出结点A到结点B的路径上的点对应的权值的和。

给出q个操作,要求在线处理所有操作。

输入输出格式

输入格式:

第一行包含一个整数n(1<=n<=30000),表示节点的数目。

第二行包含n个整数,第i个整数表示第i个节点初始时对应的权值。

第三行包含一个整数q(1<=n<=300000),表示操作的数目。

以下q行,每行包含一个操作,操作的类别见题目描述。

任意时刻每个节点对应的权值都是1到1000的整数。

输出格式:

输出所有bridge操作和excursion操作对应的输出,每个一行。

输入输出样例

输入样例#1: 
5
4 2 4 5 6
10
excursion 1 1
excursion 1 2
bridge 1 2
excursion 1 2
bridge 3 4
bridge 3 5
excursion 4 5
bridge 1 3
excursion 2 4
excursion 2 5
输出样例#1: 
4
impossible
yes
6
yes
yes
15
yes
15
16





说明

数据范围:1<=n<=30000, 1<=q<=300000, 0<=wi<=1000。

裸的LCT。。。

直接上板子。。。

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 40010
using namespace std;
int n,m,w[MAXN];
int top,stack[MAXN];
struct node{
	int f,flag,son[2];
	int v;
}a[MAXN];
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
inline bool isroot(int rt){
	return a[a[rt].f].son[0]!=rt&&a[a[rt].f].son[1]!=rt;
}
inline void pushup(int rt){
	if(!rt)return;
	a[rt].v=w[rt]+a[a[rt].son[0]].v+a[a[rt].son[1]].v;
}
inline void pushdown(int rt){
	if(!rt||!a[rt].flag)return;
	a[a[rt].son[0]].flag^=1;a[a[rt].son[1]].flag^=1;a[rt].flag^=1;
	swap(a[rt].son[0],a[rt].son[1]);
}
inline void turn(int rt){
	int x=a[rt].f,y=a[x].f,k=a[x].son[0]==rt?1:0;
	if(!isroot(x)){
		if(a[y].son[0]==x)a[y].son[0]=rt;
		else a[y].son[1]=rt;
	}
	a[rt].f=y;a[x].f=rt;a[a[rt].son[k]].f=x;
	a[x].son[k^1]=a[rt].son[k];a[rt].son[k]=x;
	pushup(x);pushup(rt);
}
void splay(int rt){
	top=0;
	stack[++top]=rt;
	for(int i=rt;!isroot(i);i=a[i].f)stack[++top]=a[i].f;
	while(top)pushdown(stack[top--]);
	while(!isroot(rt)){
		int x=a[rt].f,y=a[x].f;
		if(!isroot(x)){
			if((a[y].son[0]==x)^(a[x].son[0]==rt))turn(rt);
			else turn(x);
		}
		turn(rt);
	}
}
void access(int rt){
	for(int i=0;rt;i=rt,rt=a[rt].f){
		splay(rt);
		a[rt].son[1]=i;
		pushup(rt);
	}
}
inline void makeroot(int rt){access(rt);splay(rt);a[rt].flag^=1;}
int find(int rt){
	access(rt);splay(rt);
	while(a[rt].son[0])rt=a[rt].son[0];
	return rt;
}
inline void split(int x,int y){makeroot(x);access(y);splay(y);}
inline void link(int x,int y){makeroot(x);a[x].f=y;}
inline void cut(int x,int y){split(x,y);a[y].son[0]=a[x].f=0;}
void work(){
	char ch[20];
	int x,y;
	m=read();
	while(m--){
		scanf("%s",ch);x=read();y=read();
		if(ch[0]=='b'){
			int fx=find(x),fy=find(y);
			if(fx==fy)printf("no\n");
			else{
				printf("yes\n");
				link(x,y);
			}
		}
		if(ch[0]=='p'){
			access(x);splay(x);w[x]=y;pushup(x);
		}
		if(ch[0]=='e'){
			int fx=find(x),fy=find(y);
			if(fx!=fy)printf("impossible\n");
			else{
				split(x,y);
				printf("%d\n",a[y].v);
			}
		}
	}
}
void init(){
	n=read();
	for(int i=1;i<=n;i++)a[i].v=w[i]=read();
}
int main(){
	init();
	work();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值