bzoj 1180(link cut tree)

1180: [CROATIAN2009]OTOCI

Time Limit: 50 Sec   Memory Limit: 162 MB
Submit: 807   Solved: 503
[ Submit][ Status][ Discuss]

Description

给出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个操作,要求在线处理所有操作。数据范围:1<=n<=30000, 1<=q<=300000, 0<=wi<=1000。

Input

第一行包含一个整数n(1<=n<=30000),表示节点的数目。第二行包含n个整数,第i个整数表示第i个节点初始时对应的权值。第三行包含一个整数q(1<=n<=300000),表示操作的数目。以下q行,每行包含一个操作,操作的类别见题目描述。任意时刻每个节点对应的权值都是1到1000的整数。

Output

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

Sample Input

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

Sample Output

4
impossible
yes
6
yes
yes
15
yes
15

16


解题思路:link cut tree模板题(50min)


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int n,m;
int sum[30005],rever[30005],l[30005],r[30005],zhi[30005],f[30005];
int q[30005];


inline long long read()
 {
  char y; long long x=0,f=1; y=getchar();
  while (y<'0'||y>'9') {if (y=='-') f=-1; y=getchar();}
  while (y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;
 }


void maindown(int now)
 {
  sum[now]=sum[l[now]]+sum[r[now]]+zhi[now];
 }


void pushdown(int now)
 {
  if (rever[now])
  {
  rever[now]^=1;
  if (l[now]!=0)rever[l[now]]^=1;
  if (r[now]!=0)rever[r[now]]^=1;
  swap(l[now],r[now]);
 }
 }


bool root(int now)
 {
  if (l[f[now]]==now || r[f[now]]==now) return true;else return false;
 }


void rotate(int x)
 {
  int y=f[x]; int z=f[y];
  if (root(y))
  {
  if (l[z]==y) l[z]=x; else r[z]=x;
}
f[y]=x; f[x]=z;
  if (l[y]==x)
  {
  f[r[x]]=y; l[y]=r[x]; r[x]=y;
 }else
  {
    f[l[x]]=y; r[y]=l[x]; l[x]=y; 
  }
maindown(y); maindown(x);
 }


void splay(int x)
 {
  int now=x; int tail=0; ++tail; q[tail]=x; 
  while(root(now))
  {
   ++tail; q[tail]=f[now];
   now=f[now];
}
for (int i=tail;i>=1;--i) pushdown(q[i]);
while (root(x))
{
int y=f[x]; int z=f[y];
if (root(y))
{
if (l[y]==x ^ l[z]==y) rotate(x);else rotate(y);
    }
rotate(x);
}
 }


void access(int now)
 {
  splay(now);
  while (f[now]!=0)
  {
  r[now]=0; maindown(now);
  splay(f[now]); r[f[now]]=now; maindown(f[now]);
  splay(now); 
}
r[now]=0; maindown(now);
 }


void makeroot(int now)
 {
  access(now); rever[now]^=1;
 }


int find(int now)
 {
  while (l[now]!=0) now=l[now];
  return now;
 }


void link(int a,int b)
 {
  makeroot(a); f[a]=b;
 }


int main()
{
n=read();
for (int i=1;i<=n;++i)
{
zhi[i]=read(); f[i]=0; sum[i]=zhi[i];
}
    m=read();
for (int i=1;i<=m;++i)
{
char s[10]; int a,b;
scanf("%s",s); a=read(); b=read();
if (s[0]=='b')
{
access(a); int u1=find(a);
access(b); int u2=find(b);
if (u1==u2) printf("no\n"); else {printf("yes\n");link(a,b);}
}
if (s[0]=='p')
{
access(a); sum[a]=sum[a]-zhi[a]+b; zhi[a]=b;
}
if (s[0]=='e')
{
access(a); int u1=find(a);
access(b); int u2=find(b);
if (u1!=u2) printf("impossible\n");else {makeroot(a); access(b); printf("%d\n",sum[b]);}
}
}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值