Q-Tree系列

树型结构最好的练习题。

Q-Tree Ⅰ

树链剖分维护边权,线段树区间最大值。

P4114SP375

你以为是双倍经验?其实是双倍经验

洛谷里的题而言,就是一个普普通通的边权挂点。但是,在 $SPOJ$ 里,你会发现提交 c++ 语言的提交都显示 waiting ,而那些 $AC$ 了的,都用的是 c 语言。

所以为了拿到这双倍经验我还去学了一下 c 语言的语法

c 语言语法如下:

  1. c 语言中没有 iostreamalgorithm 的头文件;
  2. c- 开头的头文件需要换成 -h 的头文件,如 cstdio 换成 stdio.h 等;
  3. 不能使用 const 以及 structtemplate
  4. 所以类似于 maxswap 之类的函数需要手写。

这是这道题需要注意的。

AC Code for C++ ver
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<ctime>
#include<iomanip>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#define gh() getchar()
#define re register
#define db double
#define ls p<<1
#define rs p<<1|1
typedef long long ll;
using namespace std;
const int MAXN=1e5+1;
const int INF=0x7f7f7f7f;
template<class T>
inline void read(T &x)
{
x=0;
char ch=gh(),t=0;
while(ch<'0'||ch>'9') t|=ch=='-',ch=gh();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=gh();
if(t) x=-x;
}
template<class T,class ...T1>
inline void read(T &x,T1 &...x1)
{
read(x),read(x1...);
}
template<class T>
inline bool checkMax(T &x,T &y)
{
return x<y?x=y,1:0;
}
template<class T>
inline bool checkMin(T &x,T &y)
{
return x>y?x=y,1:0;
}
int N;
struct Graph
{
int next,to,val;
Graph(int n=0,int t=0,int v=0):next(n),to(t),val(v){}
}Edge[MAXN<<1];
int Head[MAXN],Total,Idx[MAXN],Bck[MAXN];
inline void addEdge(int u,int v,int w)
{
Edge[++Total]=Graph(Head[u],v,w);Head[u]=Total;
Edge[++Total]=Graph(Head[v],u,w);Head[v]=Total;
}
int Fa[MAXN],Son[MAXN],Size[MAXN],Dep[MAXN],Path[MAXN];
void dfsTree(int x,int last)
{
Fa[x]=last,Size[x]=1,Dep[x]=Dep[last]+1;
for(int e=Head[x],v;e;e=Edge[e].next)
{
if((v=Edge[e].to)==last) continue;
Path[v]=Edge[e].val;
dfsTree(v,x);
Size[x]+=Size[v];
if(!Son[x]||Size[Son[x]]<Size[v]) Son[x]=v;
}
}
int Top[MAXN],Dfn[MAXN],Val[MAXN],Cnt;
void dfs_Seg(int x,int topf)
{
Dfn[x]=++Cnt;
Val[Cnt]=Path[x],Top[x]=topf;
if(!Son[x]) return ;
dfs_Seg(Son[x],topf);
for(int e=Head[x],v;e;e=Edge[e].next)
{
if((v=Edge[e].to)==Fa[x]||v==Son[x]) continue;
dfs_Seg(v,v);
}
}
struct SegmentTree
{
int l,r,val;
}Tree[MAXN<<2];
inline void pushUp(int p)
{
Tree[p].val=max(Tree[ls].val,Tree[rs].val);
}
void build(int p,int l,int r)
{
Tree[p].l=l,Tree[p].r=r;
if(l==r)
{
Tree[p].val=Val[l];
return ;
}
int mid=(l+r)>>1;
build(ls,l,mid),build(rs,mid+1,r);
pushUp(p);
}
void modify(int p,int d,int k)
{
if(d<=Tree[p].l&&Tree[p].r<=d)
{
Tree[p].val=k;
return ;
}
int mid=(Tree[p].l+Tree[p].r)>>1;
if(d<=mid) modify(ls,d,k);
if(mid<d) modify(rs,d,k);
pushUp(p);
}
int query(int p,int l,int r)
{
if(l<=Tree[p].l&&Tree[p].r<=r) return Tree[p].val;
int val=-INF;
int mid=(Tree[p].l+Tree[p].r)>>1;
if(l<=mid) val=max(val,query(ls,l,r));
if(mid<r) val=max(val,query(rs,l,r));
return val;
}
inline int queryPath(int x,int y)
{
int res=-INF;
while(Top[x]!=Top[y])
{
if(Dep[Top[x]]<Dep[Top[y]]) swap(x,y);
res=max(res,query(1,Dfn[Top[x]],Dfn[x]));
x=Fa[Top[x]];
}
if(Dep[x]>Dep[y]) swap(x,y);
res=max(res,query(1,Dfn[x]+1,Dfn[y]));
return res;
}
char Str[256];
int x,y;
int main()
{
// freopen("tree-chain.in","r",stdin);
// freopen("tree-chain.out","w",stdout);
read(N);
for(int i=2,u,v,w;i<=N;++i)
{
read(u,v,w);
addEdge(u,v,w);
Bck[i-1]=u,Idx[i-1]=v;
}
dfsTree(1,0);
dfs_Seg(1,1);
build(1,1,N);
for(int i=1;i<N;++i)
Idx[i]=(Bck[i]==Fa[Idx[i]]?Idx[i]:Bck[i]);
scanf("%s",Str+1);
while(Str[1]!='D')
{
read(x,y);
if(Str[1]=='Q')
{
if(x==y) puts("0");
else printf("%d\n",queryPath(x,y));
}
else modify(1,Dfn[Idx[x]],y);
scanf("%s",Str+1);
}
/*for(int i=1;i<=N;++i) printf("%d ",Dfn[i]);
puts("");
for(int i=1;i<N;++i) printf("%d ",Idx[i]);*/
return 0;
}
/*
3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE
6
1 2 3
1 3 1
3 4 2
3 5 5
5 6 4
QUERY 4 2
CHANGE 2 6
QUERY 1 6
QUERY 5 4
CHANGE 4 2
QUERY 4 6
QUERY 2 6
DONE
*/

AC Code for c ver.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdlib.h>
#define gh() getchar()
#define re register
#define ls p<<1
#define rs p<<1|1
#define MAXN 100001
#define INF 0x7f7f7f7f
typedef long long ll;
int N,Test;
int Next[MAXN<<1],To[MAXN<<1],Wt[MAXN<<1];
int Head[MAXN],Total,Idx[MAXN],Bck[MAXN];
int Fa[MAXN],Son[MAXN],Siz[MAXN],Dep[MAXN],Path[MAXN];
int Top[MAXN],Dfn[MAXN],Val[MAXN],Cnt;
int L[MAXN<<2],R[MAXN<<2],val[MAXN<<2];
int x,y;
char Str[256];
int max(int a,int b){ return a>b?a:b; }
#define swap(A, B) \
{ \
int __T = A; \
A = B; \
B = __T; \
}
void addEdge(int u,int v,int w)
{
Next[++Total]=Head[u];
To[Total]=v;
Wt[Total]=w;
Head[u]=Total;
Next[++Total]=Head[v];
To[Total]=u;
Wt[Total]=w;
Head[v]=Total;
}
void dfsTree(int x,int last)
{
Fa[x]=last,Siz[x]=1,Dep[x]=Dep[last]+1;
for(int e=Head[x],v;e;e=Next[e])
{
if((v=To[e])==last) continue;
Path[v]=Wt[e];
dfsTree(v,x);
Siz[x]+=Siz[v];
if(!Son[x]||Siz[Son[x]]<Siz[v]) Son[x]=v;
}
}
void dfs_Seg(int x,int topf)
{
Dfn[x]=++Cnt;
Val[Cnt]=Path[x],Top[x]=topf;
if(!Son[x]) return ;
dfs_Seg(Son[x],topf);
for(int e=Head[x],v;e;e=Next[e])
{
if((v=To[e])==Fa[x]||v==Son[x]) continue;
dfs_Seg(v,v);
}
}
void pushUp(int p)
{
val[p]=max(val[ls],val[rs]);
}
void build(int p,int l,int r)
{
L[p]=l,R[p]=r;
if(l==r)
{
val[p]=Val[l];
return ;
}
int mid=(l+r)>>1;
build(ls,l,mid),build(rs,mid+1,r);
pushUp(p);
}
void modify(int p,int d,int k)
{
if(d<=L[p]&&R[p]<=d)
{
val[p]=k;
return ;
}
int mid=(L[p]+R[p])>>1;
if(d<=mid) modify(ls,d,k);
if(mid<d) modify(rs,d,k);
pushUp(p);
}
int query(int p,int l,int r)
{
if(l<=L[p]&&R[p]<=r) return val[p];
int res=-INF;
int mid=(L[p]+R[p])>>1;
if(l<=mid) res=max(res,query(ls,l,r));
if(mid<r) res=max(res,query(rs,l,r));
return res;
}
int queryPath(int x,int y)
{
int res=-INF;
while(Top[x]!=Top[y])
{
if(Dep[Top[x]]<Dep[Top[y]]) swap(x,y);
res=max(res,query(1,Dfn[Top[x]],Dfn[x]));
x=Fa[Top[x]];
}
if(Dep[x]>Dep[y]) swap(x,y);
res=max(res,query(1,Dfn[x]+1,Dfn[y]));
return res;
}
void init()
{
Cnt=Total=0;
memset(Head,0,sizeof(Head));
memset(Son,0,sizeof(Son));
}
int main()
{
// freopen("tree-chain.in","r",stdin);
// freopen("tree-chain.out","w",stdout);
scanf("%d",&Test);
while(Test--)
{
scanf("%d",&N);
init();
for(int i=2,u,v,w;i<=N;++i)
{
scanf("%d%d%d",&u,&v,&w);
addEdge(u,v,w);
Bck[i-1]=u,Idx[i-1]=v;
}
dfsTree(1,0);
dfs_Seg(1,1);
build(1,1,N);
for(int i=1;i<N;++i)
Idx[i]=(Bck[i]==Fa[Idx[i]]?Idx[i]:Bck[i]);
scanf("%s",Str+1);
while(Str[1]!='D')
{
scanf("%d%d",&x,&y);
if(Str[1]=='Q')
{
if(x==y) puts("0");
else printf("%d\n",queryPath(x,y));
}
else modify(1,Dfn[Idx[x]],y);
scanf("%s",Str+1);
}
}
return 0;
}
/*
3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE
6
1 2 3
1 3 1
3 4 2
3 5 5
5 6 4
QUERY 4 2
CHANGE 2 6
QUERY 1 6
QUERY 5 4
CHANGE 4 2
QUERY 4 6
QUERY 2 6
DONE
*/

Q-Tree Ⅱ


Q-Tree Ⅲ

P4092 [HEOI2016/TJOI2016]树 有些相似。但是这道题可以反转操作。

逛了一圈题解,结果发现没几个人写的是线段树,甚至还有写 $\text{Link-Cut Tree}$ 的,全是巨佬。

$\text{stO 神犇 Orz}$

所以我也写的是树剖维护 std::set ,将每一条链里黑颜色的结点全部存到其链顶,每次取最近的。所以修改操作就一个 insert 一个 erase 就完事儿了。

然后查询,直接暴力跳即可。

AC Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<ctime>
#include<iomanip>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<vector>
#define gh() getchar()
#define re register
typedef long long ll;
const int MAXN=1e5+1;
const int INF=0x3f3f3f3f;
template<class T>
inline void read(T &x)
{
x=0;
char ch=gh(),t=0;
while(ch<'0'||ch>'9') t|=ch=='-',ch=gh();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=gh();
if(t) x=-x;
}
template<class T,class ...T1>
inline void read(T &x,T1 &...x1)
{
read(x),read(x1...);
}
template<class T>
inline void write(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
template<class T>
inline bool checkMax(T &x,T &y)
{
return x<y?x=y,1:0;
}
template<class T>
inline bool checkMin(T &x,T &y)
{
return x>y?x=y,1:0;
}
int N,Q;
struct TC
{
int next,to;
}Edge[MAXN<<1];
int Head[MAXN],Total;
inline void addEdge(int u,int v)
{
Edge[++Total]=(TC){Head[u],v};Head[u]=Total;
Edge[++Total]=(TC){Head[v],u};Head[v]=Total;
}
int Fa[MAXN],Dep[MAXN],Size[MAXN],Son[MAXN];
void dfsTree(int x,int last)
{
Fa[x]=last,Dep[x]=Dep[last]+1,Size[x]=1;
for(int e=Head[x],v;e;e=Edge[e].next)
{
if((v=Edge[e].to)==last) continue;
dfsTree(v,x);
Size[x]+=Size[v];
if(!Son[x]||Size[v]>Size[Son[x]]) Son[x]=v;
}
}
int Top[MAXN],Dfn[MAXN],Bck[MAXN],Cnt;
void dfsSeg(int x,int topf)
{
Top[x]=topf,Dfn[++Cnt]=x;Bck[x]=Cnt;
if(!Son[x]) return ;
dfsSeg(Son[x],topf);
for(int e=Head[x],v;e;e=Edge[e].next)
{
if((v=Edge[e].to)==Fa[x]||v==Son[x]) continue;
dfsSeg(v,v);
}
}
bool Col[MAXN];
int opt,Qx;
std::set<int>St[MAXN];
int main()
{
// freopen("tree-chain.in","r",stdin);
// freopen("tree-chain.out","w",stdout);
read(N,Q);
for(int i=2,u,v;i<=N;++i)
{
read(u,v);addEdge(u,v);
}
dfsTree(1,0),dfsSeg(1,1);
while(Q--)
{
read(opt,Qx);
if(opt==1)
{
int res=INF;
while(Qx)
{
int k=*St[Top[Qx]].begin();
if(St[Top[Qx]].size())
if(Dep[Dfn[k]]<=Dep[Qx]) res=Dfn[k];
Qx=Fa[Top[Qx]];
}
write(res==INF?-1:res),puts("");
}
else
{
Col[Qx]^=1;
if(Col[Qx]) St[Top[Qx]].insert(Bck[Qx]);
else St[Top[Qx]].erase(Bck[Qx]);
}
}
return 0;
}
/*
9 8
1 2
1 3
2 4
2 9
5 9
7 9
8 9
6 8
1 3
0 8
1 6
1 7
0 2
1 9
0 2
1 9
*/