Query on The Trees
Problem Description
We have met so many problems on the tree, so today we will have a query problem on a set of trees.
There are nodes, each node will have a unique weight . We will have four kinds of operations on it and you should solve them efficiently. Wish you have fun!
Input
There are multiple test cases in our dataset.
For each case, the first line contains only one integer The next lines each contains two integers which means there is an edge between them. It also means we will give you one tree initially.
The next line will contains integers which means the weight of each node.
The next line will contains an integer The next lines will start with an integer or means the kind of this operation.
- Given two integer you should make a new edge between these two node and . So after this operation, two trees will be connected to a new one.
- Given two integer you should find the tree in the tree set who contain node , and you should make the node be the root of this tree, and then you should cut the edge between node and its parent. So after this operation, a tree will be separate into two parts.
- Given three integer for the and all nodes between the path from to , you should increase their weight by
- Given two integer you should check the node weights on the path between and , and you should output the maximum weight on it.
Output
For each query you should output the correct answer of it. If you find this query is an illegal operation, you should output .
You should output a blank line after each test case.
Sample Input
5
1 2
2 4
2 5
1 3
1 2 3 4 5
6
4 2 3
2 1 2
4 2 3
1 3 5
3 2 1 4
4 1 4
Sample Output
3
-1
7
Hint
We define the illegal situation of different operations:
In first operation: if node and belong to a same tree, we think it’s illegal.
In second operation: if or and not belong to a same tree, we think it’s illegal.
In third operation: if and not belong to a same tree, we think it’s illegal.
In fourth operation: if and not belong to a same tree, we think it’s illegal.
Source
The 36th ACM/ICPC Asia Regional Dalian Site —— Online Contest
題意
- 開始給你一顆帶點權的樹,然後實現一下操作
- 連接
- 讓成爲樹根,然後分離出以爲根的子樹
- 讓到的路徑上的所有節點的權值加上
- 查詢從到的簡單路徑上的最大點權
題解
- 雖然是一個比較簡單的,但是還是有很多需要注意的地方
- 自己實現一些的函數時,要注意是否需要下放標記,上傳標記,比如上述第個操作,稍不注意可能就會
- 對於實現的一些簡單路徑所有節點修改操作,可以將標記放在區間翻轉操作一起,同步下放標記,所以很好維護 ,只用修改函數就行了
- 本題一個小坑就是多組數據,然後修改操作如果不合法也需要輸出
代碼
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+10;
#define inf 0x3f3f3f3f
namespace IO{
#define BUF_SIZE 100000
#define OUT_SIZE 100000
bool IOerror=0;
inline char nc(){
static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
if(p1==pend){
p1=buf;pend=buf+fread(buf,1,BUF_SIZE,stdin);
if(pend==p1){IOerror=1;return -1;}
}
return *p1++;
}
inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';}
inline bool read(double &x){
bool sign=0; char ch=nc(); x=0;
for(;blank(ch);ch=nc());
if(IOerror) return false;
if(ch=='-')sign=1,ch=nc();
for(;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if(ch=='.'){
double tmp=1;ch=nc();
for(;ch>='0'&&ch<='9';ch=nc())tmp/=10.0,x+=tmp*(ch-'0');
}
if(sign)x=-x;return true;
}
template<typename T>
inline bool read(T &x){
bool sign=0; char ch=nc(); x=0;
for(;blank(ch);ch=nc());
if(IOerror) return false;
if(ch=='-')sign=1,ch=nc();
for(;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0';
if(sign)x=-x; return true;
}
inline bool read(char *s){
char ch=nc();
for(;blank(ch);ch=nc());
if(IOerror) return false;
for(;!blank(ch)&&!IOerror;ch=nc())*s++=ch;
*s=0;return true;
}
};
using namespace IO;
namespace LCT{
int ch[maxn][2],fa[maxn],mark[maxn];
long long val[maxn],ans[maxn],lazy[maxn];
inline bool not_root(int x) {return ch[fa[x]][0]==x||ch[fa[x]][1]==x;}
inline int dir(int x) {return ch[fa[x]][1]==x;}
inline void add_mark(int x) {swap(ch[x][0],ch[x][1]);mark[x]^=1;} //將x這顆子樹翻轉
inline void push_down(int x) {
if(mark[x]) {
if(ch[x][0]) add_mark(ch[x][0]);
if(ch[x][1]) add_mark(ch[x][1]);
mark[x]=0;
}
if(lazy[x]) {
if(ch[x][0]) {
lazy[ch[x][0]]+=lazy[x];
val[ch[x][0]]+=lazy[x];
ans[ch[x][0]]+=lazy[x];
}
if(ch[x][1]) {
lazy[ch[x][1]]+=lazy[x];
val[ch[x][1]]+=lazy[x];
ans[ch[x][1]]+=lazy[x];
}
lazy[x]=0;
}
}
inline void push_up(int x) {
ans[x]=val[x];
if(ch[x][0]) ans[x]=max(ans[x],ans[ch[x][0]]);
if(ch[x][1]) ans[x]=max(ans[x],ans[ch[x][1]]);
}
inline void pushall(int x) {
if(not_root(x)) pushall(fa[x]);
push_down(x);
}
inline void rotate(int x){
int y=fa[x],z=fa[y],k=dir(x);
if(ch[x][k^1]) fa[ch[x][k^1]]=y;ch[y][k]=ch[x][k^1];
if(not_root(y)) ch[z][dir(y)]=x;fa[x]=z;
ch[x][k^1]=y;fa[y]=x;
push_up(y);push_up(x);
}
inline void splay(int x,int goal=0) {
pushall(x);
while(not_root(x)) {
int y=fa[x],z=fa[y];
if(not_root(y)) {
if(dir(x)==dir(y)) rotate(y);
else rotate(x);
}
rotate(x);
}
//push_up(x);
}
inline void access(int x) { //從原樹的根向x拉一條實鏈
for(int y=0;x;y=x,x=fa[x]) {
splay(x);ch[x][1]=y;push_up(x);
}
}
inline void make_root(int x) { //使x成爲splay的根
access(x);splay(x);add_mark(x);
}
inline int find_root(int x) { //找到x在原樹中的根
access(x);splay(x);
while(ch[x][0]) push_down(x),x=ch[x][0];
splay(x);
return x;
}
inline void split(int x,int y) { //拉出一條x->y的實鏈,y爲splay根
make_root(x);access(y);splay(y);
}
inline bool link(int x,int y) { //連接x與y,若已經在同一顆原樹中,返回0
make_root(x);
fa[x]=y;return 1;
}
inline bool cut(int x,int y) {
make_root(x);
if(find_root(y)!=x||fa[y]!=x||ch[y][0]) return 0;
fa[y]=ch[x][1]=0;
push_up(x);
return 1;
}
inline long long query_max(int l,int r) {
split(l,r);
return ans[r];
}
};
using namespace LCT;
int n,m,opt,u[maxn],v[maxn];
int main()
{
while(read(n)) {
for(int i=1;i<n;i++) read(u[i]),read(v[i]);
for(int i=1;i<=n;i++) read(val[i]);
for(int i=1;i<n;i++) link(u[i],v[i]);
read(m);
for(int i=1,u,v,w;i<=m;i++) {
read(opt),read(u),read(v);
if(opt==1) {
if(find_root(u)==find_root(v)) printf("-1\n");
else link(u,v);
}
else if(opt==2) {
if(u==v||find_root(u)!=find_root(v)) {
printf("-1\n");
continue;
}
split(u,v);
push_down(v);push_down(ch[v][0]);
int f=ch[v][0];
while(ch[f][1]) {f=ch[f][1];push_down(f);}
cut(v,f);
}else if(opt==3) {
read(w);
if(find_root(v)!=find_root(w)) {
printf("-1\n");
continue;
}
split(v,w);
ans[w]+=u;
lazy[w]+=u;
val[w]+=u;
}else {
if(find_root(u)!=find_root(v)) printf("-1\n");
else printf("%lld\n",query_max(u,v));
}
}
for(int i=1;i<=n;i++) val[i]=mark[i]=lazy[i]=ans[i]=ch[i][0]=ch[i][1]=fa[i]=0;
printf("\n");
}
}