A. Censoring
题目描述
$FJ$把杂志上所有的文章摘抄了下来并把它变成了一个长度不超过$10^5$的字符串$S$。他有一个包含$n$个单词的列表,列表里的$n$个单词记为$t_1……t_N$。他希望从$S$中删除这些单词。
$FJ$每次在$S$中找到最早出现的列表中的单词(最早出现指该单词的开始位置最小),然后从$S$中删除这个单词。他重复这个操作直到$S$中没有列表里的单词为止。注意删除一个单词后可能会导致$S$中出现另一个列表中的单词
$FJ$注意到列表中的单词不会出现一个单词是另一个单词子串的情况,这意味着每个列表中的单词在$S$中出现的开始位置是互不相同的
请帮助$FJ$完成这些操作并输出最后的$S$
输入格式
第一行包含一个字符串$S$
第二行包含一个整数$N,N<2000$ 接下来的$N$行,每行包含一个字符串,第$i$行的字符串是$t_i$
输出格式
一行,输出操作后的$S$
样例
样例输入
begintheescapexecutionatthebreakofdawn
2
escape
execution
样例输出
beginthatthebreakofdawn
题解


#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<queue>
#define Reg register
using namespace std;
int n,front,stack[100050],len[2050];
char s[100050],ls[100050];
struct Tree {Tree *next[26],*fail;int rank;};
Tree *New()
{
Tree *p=new Tree;
for(Reg int i=0;i<26;++i) p->next[i]=NULL;
p->fail=NULL;
p->rank=0;
return p;
}
Tree *root=New();
Tree *pos[100050];
void Insert(char s[],int k)
{
int l=strlen(s);
len[k]=l;
Tree *p=root;
for(Reg int i=0,x;i<l;++i)
{
x=s[i]-'a';
if(p->next[x]==NULL) p->next[x]=New();
p=p->next[x];
}
p->rank=k;
return;
}
void GetFail()
{
queue<Tree *> q;
q.push(root);
while(!q.empty())
{
Tree *p=q.front(); q.pop();
for(Reg int i=0;i<26;++i)
{
if(p->next[i]==NULL) continue;
if(p==root) p->next[i]->fail=root;
else
{
Tree *tmp=p->fail;
while(tmp!=NULL)
{
if(tmp->next[i]!=NULL)
{
p->next[i]->fail=tmp->next[i];
break;
}
tmp=tmp->fail;
}
if(tmp==NULL) p->next[i]->fail=root;
}
q.push(p->next[i]);
}
}
return;
}
void GetAc(char s[])
{
int l=strlen(s);
Tree *p=root;
for(Reg int i=0;i<l;++i)
{
stack[++front]=s[i]-'a';
int x=stack[front];
while(p!=NULL&&p->next[x]==NULL) p=p->fail;
if(p==NULL) p=root;
else
{
p=p->next[x];
if(p->rank>0)
{
front-=len[p->rank];
p=pos[i-len[p->rank]];
}
}
pos[i]=p;
}
for(Reg int i=1;i<=front;++i)
printf("%c",(char)stack[i]+'a');
return;
}
int main()
{
scanf("%s",s);
scanf("%d",&n);
for(Reg int i=1;i<=n;++i)
{
scanf("%s",ls);
Insert(ls,i);
}
GetFail();
GetAc(s);
return 0;
}
改正$AC$自动机代码($TLE 93$)


#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<queue>
#define Reg register
using namespace std;
int n,front,stack[1000050],len[1000050];
char s[1000050],ls[1000050];
struct Tree {Tree *next[26],*fail;int rank;};
Tree *New()
{
Tree *p=new Tree;
for(Reg int i=0;i<26;++i) p->next[i]=NULL;
p->fail=NULL;
p->rank=0;
return p;
}
Tree *root=New();
Tree *pos[1000050];
void Insert(char s[],int k)
{
int l=strlen(s);
len[k]=l;
Tree *p=root;
for(Reg int i=0;i<l;++i)
{
int x=s[i]-'a';
if(p->next[x]==NULL) p->next[x]=New();
p=p->next[x];
}
p->rank=k;
return;
}
void GetFail()
{
queue<Tree *> q;
q.push(root);
root->fail=NULL;
while(!q.empty())
{
Tree *p=q.front(); q.pop();
for(Reg int i=0;i<26;++i)
{
if(p->next[i]==NULL) continue;
if(p==root) p->next[i]->fail=root;
else
{
Tree *tmp=p->fail;
while(tmp!=NULL)
{
if(tmp->next[i]!=NULL)
{
p->next[i]->fail=tmp->next[i];
break;
}
tmp=tmp->fail;
}
if(tmp==NULL) p->next[i]->fail=root;
}
q.push(p->next[i]);
}
}
return;
}
void GetAc(char s[])
{
int l=strlen(s);
Tree *p=root;
pos[0]=root;
for(Reg int i=0;i<l;++i)
{
stack[++front]=s[i]-'a';
int x=stack[front];
while(p->next[x]==NULL&&p!=root) p=p->fail;
p=p->next[x];
if(p==NULL) p=root;
pos[front]=p;
if(p->rank>0)
{
front-=len[p->rank];
p=pos[front];
}
}
for(Reg int i=1;i<=front;++i)
printf("%c",(char)stack[i]+'a');
return;
}
int main()
{
scanf("%s",s);
scanf("%d",&n);
for(Reg int i=1;i<=n;++i)
{
scanf("%s",ls);
Insert(ls,i);
}
GetFail();
GetAc(s);
return 0;
}
正解$Trie$图代码($AC$)


#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<queue>
#define Reg register
using namespace std;
int n,front,stack[100050],len[100050];
char s[100050],ls[100050];
struct Tree {Tree *next[26],*fail;int rank;};
Tree *New()
{
Tree *p=new Tree;
for(Reg int i=0;i<26;++i) p->next[i]=NULL;
p->fail=NULL;
p->rank=0;
return p;
}
Tree *root=New();
Tree *pos[100050];
void Insert(char s[],int k)
{
int l=strlen(s);
len[k]=l;
Tree *p=root;
for(Reg int i=0;i<l;++i)
{
int x=s[i]-'a';
if(p->next[x]==NULL) p->next[x]=New();
p=p->next[x];
}
p->rank=k;
return;
}
void GetFail()
{
queue<Tree *> q;
q.push(root);
while(!q.empty())
{
Tree *p=q.front(); q.pop();
for(Reg int i=0;i<26;++i)
{
if(p->next[i]!=NULL)
{
if(p==root) p->next[i]->fail=p;
else p->next[i]->fail=p->fail->next[i];
q.push(p->next[i]);
}
else
{
if(p==root) p->next[i]=p;
else p->next[i]=p->fail->next[i];
}
}
}
return;
}
void GetAc(char s[])
{
int l=strlen(s);
Tree *p=root;
pos[0]=root;
for(Reg int i=0;i<l;++i)
{
stack[++front]=s[i]-'a';
int x=stack[front];
p=p->next[x];
pos[front]=p;
if(p->rank>0)
{
front-=len[p->rank];
p=pos[front];
}
}
for(Reg int i=1;i<=front;++i)
printf("%c",(char)stack[i]+'a');
return;
}
int main()
{
scanf("%s",s);
scanf("%d",&n);
for(Reg int i=1;i<=n;++i)
{
scanf("%s",ls);
Insert(ls,i);
}
GetFail();
GetAc(s);
return 0;
}
其实改动不大,就是$Trie$图没有看过。
B. 记忆的轮廓
题目描述
通往贤者之塔的路上,有许多的危机。
我们可以把这个地形看做是一颗树,根节点编号为$1$,目标节点编号为$n$,其中$1-n$的简单路径上,编号依次递增,在$[1,n]$中,一共有$n$个节点。我们把编号在$[1,n]$的叫做正确节点,$[n+1,m]$的叫做错误节点。一个叶子,如果是正确节点则为正确叶子,否则称为错误叶子。莎缇拉要帮助昴到达贤者之塔,因此现在面临着存档位置设定的问题。
为了让昴成长为英雄,因此一共只有$p$次存档的机会,其中$1$和$n$必须存档。被莎缇拉设置为要存档的节点称为存档位置。当然不能让昴陷入死循环,所以存档只能在正确节点上进行,而且同一个节点不能存多次档。因为通往贤者之塔的路上有影响的瘴气,因此莎缇拉假设昴每次位于树上一个节点时,都会等概率选择一个儿子走下去。每当走到一个错误叶子时,再走一步就会读档。具体的,每次昴到达一个新的存档位置,存档点便会更新为这个位置(假如现在的存档点是$i$,现在走到了一个存档位置$j>i$,那么存档点便会更新为$j$)。读档的意思就是回到当前存档点。初始昴位于$1$,当昴走到正确节点$n$时,便结束了路程。莎缇拉想知道,最优情况下,昴结束路程的期望步数是多少?
输入格式
第一行一个正整数$T$表示数据组数。
接下来每组数据,首先读入三个正整数$n,m,p$。
接下来$m-n$行,描述树上所有的非正确边(正确边即连接两个正确节点的边)
用两个正整数$j$,$k$表示$j$与$k$之间有一条连边,$j$和$k$可以均为错误节点,也可以一个为正确节点另一个为错误节点。
数据保证$j$是$k$的父亲。
$50<=p<=n<=700$,$m<=1500$,$T<=5$。
数据保证每个正确节点均有至少$2$个儿子,至多$3$个儿子。
输出格式
$T$行每行一个实数表示每组数据的答案。请保留四位小数。
样例
样例输入
1
3 7 2
1 4
2 5
3 6
3 7
样例输出
9.0000


#include<iostream>
#include<cstring>
#include<cstdio>
#define Reg register
using namespace std;
int n,m,p,t,tot,front,back,las[1550],du[1550];
double ans,g[1550],dis[1050][1050],dp[1050][1050],stack[1050];
struct Tu {int st,ed,next;} lian[100050];
void add(int x,int y)
{
lian[++tot].st=x;
lian[tot].ed=y;
lian[tot].next=las[x];
las[x]=tot;
++du[x];
return;
}
void dfs(int x)
{
g[x]=1;
for(Reg int i=las[x];i;i=lian[i].next)
{
dfs(lian[i].ed);
g[x]+=(double)g[lian[i].ed]/du[x];
}
return;
}
void erfen(int p,int l,int r,int sl,int sr)
{
int mid=(l+r)/2,k;
for(Reg int i=max(sl,mid);i<=sr;++i)
{
if(dp[i][p-1]+dis[mid][i]<dp[mid][p])
{
dp[mid][p]=dp[i][p-1]+dis[mid][i];
k=i;
}
}
if(l<=mid-1) erfen(p,l,mid-1,sl,k);
if(mid+1<=r) erfen(p,mid+1,r,k,sr);
return;
}
int main()
{
scanf("%d",&t);
while(t--)
{
memset(las,0,sizeof(las));
memset(dis,0,sizeof(dis));
memset(du,0,sizeof(du));
memset(dp,0x7f,sizeof(dp));
tot=0;
scanf("%d%d%d",&n,&m,&p);
for(Reg int i=1,x,y;i<=m-n;++i)
{
scanf("%d%d",&x,&y);
add(x,y);
}
for(Reg int i=1;i<=n-1;++i) ++du[i];
for(Reg int i=1;i<=n;++i) {dfs(i); --g[i];}
for(Reg int i=1;i<=n;++i)
{
dis[i][i]=0;
for(Reg int j=i+1;j<=n;++j)
dis[i][j]=(double)dis[i][j-1]*du[j-1]+du[j-1]+g[j-1]*du[j-1];
}
dp[n][1]=0;
for(Reg int i=2;i<=p;++i) erfen(i,1,n,1,n);
printf("%0.4lf\n",dp[1][p]);
}
return 0;
}
题解
首先用$g[x]$表示错误节点读档的期望步数,
$g[x]=1+\sum (\frac{g[son[x]]}{du[x]})$,叶子节点就是$1$。
然后用$dis[i][j]$表示正确节点 $i$到$j$的期望步数。
$dis[i][j]=dis[i][j-1]+1+\sum (\frac {g[son[j-1]]+dis[i][j]}{du[j-1]})$。
然后移项,$dis[i][j]=dis[i][j-1]\times du[j-1]+du[j-1]+g[j-1]\times du[j-1]$。
用$dis[i-1][j]$减$dis[i][j]$可得:
$dis[i-1][j]-dis[i][j]=(dis[i-1][j-1]-dis[i][j-1])\times du[j-1]$。
因为$du[j-1]>=1$,所以$dis[i-1][j]-dis[i][j]>=dis[i-1][j-1]-dis[i][j-1]$。
然后变一下,$dis[i+1][j]-dis[i][j]<=dis[i+1][j-1]-dis[i][j-1]$。
用$dp[i][k]$表示用了$k$次存档次数且在$i$存档时$i$到$n$的最短距离。
显然$dp[n][1]=0$,$dp[i][k]=\min (dp[j][k-1]+dis[i][j]),j>i$。
首先这个题存在一个推论:若$k$处取最优,那么当i增大时取最优的时侯一定是大于等于$k$的。
证明:
假设用了$k$次存档次数时 当$j=m$时,$dp[i][k]=dp[m][k-1]+dis[i][m]$取最小。
那么假设$l<m<r$,那么$dp[l][k-1]+dis[i][l]>dp[m][k-1]+dis[i][m]$,
且$dp[r][k-1]+dis[i][r]>dp[m][k-1]+dis[i][m]$。
当$i$增大$1$时,也就是$dp[i+1][k]$,
同样 $dp[i+1][k]=\min (dp[j][k-1]+dis[i+1][j])$。
那么我们比较$l$、$m$、$r$时的值。
由上面得:$dp[l][k-1]+dis[i][l]>dp[m][k-1]+dis[i][m]$,
那么当$i$又增大$1$时 只需要证明 $dp[l][k-1]+dis[i+1][l]>dp[m][k-1]+dis[i+1][m]$,
又由上面我们推出的式子 $dis[i+1][j]-dis[i][j]<=dis[i+1][j-1]-dis[i][j-1]$,
也就是说如果$i$增加$1$,$l$的增加量要比$m$大($l$的减小量要比$m$小),那么$l$会更大。
所以$l<m$,那么l始终不可能是最优解。
以此类推,则得到上面的推论。
之后就可以用二分求解,
定义$erfen(p,l,r,sl,sr)$。
先从$sl$到sr$枚举一边,找到使$mid$最优的$k$,
然后递归地找$erfen(p,l,mid-1,sl,k)$,
$erfen(p,mid+1,r,k,sr)$。
时间复杂度$O(pnlogn)$。
C. 雨天的尾巴
题目描述
$N$个点,形成一个树状结构。有$M$次发放,每次选择两个点$x$,$y$对于$x$到$y$的路径上(含$x$,$y$)每个点发一袋$Z$类型的物品。完成所有发放后,每个点存放最多的是哪种物品。
输入格式
第一行数字$N$,$M$
接下来$N-1$行,每行两个数字$a,b$,表示$a$与$b$间有一条边
再接下来$M$行,每行三个数字$x,y,z$.如题
输出格式
输出有$N$行
每i行的数字表示第i个点存放最多的物品是哪一种,如果有
多种物品的数量一样,输出编号最小的。如果某个点没有物品则输出$0$
样例
样例输入
20 50
8 6
10 6
18 6
20 10
7 20
2 18
19 8
1 6
14 20
16 10
13 19
3 14
17 18
11 19
4 11
15 14
5 18
9 10
12 15
11 14 87
12 1 87
14 3 84
17 2 36
6 5 93
17 6 87
10 14 93
5 16 78
6 15 93
15 5 16
11 8 50
17 19 50
5 4 87
15 20 78
1 17 50
20 13 87
7 15 22
16 11 94
19 8 87
18 3 93
13 13 87
2 1 87
2 6 22
5 20 84
10 12 93
18 12 87
16 10 93
8 17 93
14 7 36
7 4 22
5 9 87
13 10 16
20 11 50
9 16 84
10 17 16
19 6 87
12 2 36
20 9 94
9 2 84
14 1 94
5 5 94
8 17 16
12 8 36
20 17 78
12 18 50
16 8 94
2 19 36
10 18 36
14 19 50
4 12 50
样例输出
87
36
84
22
87
87
22
50
84
87
50
36
87
93
36
94
16
87
50
50
数据范围与提示
$1<=N,M<=100000$
$1<=a,b,x,y<=N$
$1<=z<=10^9$
题解
这个题其实就是板子+板子+板子,
看$z$的范围比$m$、$n$的范围要大得多,所以可以先离散化减少复杂度,
需要树上差分,每个节点动态建一颗线段树,维护区间内物品数量的最大值,
树上差分时只要两个端点加$1$,$lca$减$1$,$fat[lca]$减$1$。
最后倒着一遍$dfs$,$merge+ask$。
考试代码($WA 0$)


#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define Reg register
using namespace std;
int n,m,tot,sum,size,fir[100050],las[100050],vis[100050],fat[100050][25],ins[100050];
int que1[100050],que2[100050],que3[100050],lss[100050],ans[100050];
struct Tu {int st,ed,val,next;} lian[200050];
struct Tree {int lch,rch,date;} tree[8000050];
void add(int x,int y)
{
lian[++tot].st=x;
lian[tot].ed=y;
lian[tot].next=las[x];
las[x]=tot;
return;
}
void dfs(int x)
{
vis[x]=1;
for(Reg int j=1;j<=20;++j)
fat[x][j]=fat[fat[x][j-1]][j-1];
for(Reg int i=las[x];i;i=lian[i].next)
{
if(!vis[lian[i].ed])
{
fat[lian[i].ed][0]=x;
ins[lian[i].ed]=ins[x]+1;
dfs(lian[i].ed);
}
}
return;
}
int lca(int x,int y)
{
if(ins[x]<ins[y]) swap(x,y);
if(ins[x]!=ins[y])
{
for(Reg int i=20;i>=0;--i)
if(ins[fat[x][i]]>ins[y]) x=fat[x][i];
if(x==y) return x;
x=fat[x][0];
if(x==y) return x;
}
if(x==y) return x;
for(Reg int i=20;i>=0;--i)
{
if(fat[x][i]!=fat[y][i])
{
x=fat[x][i];
y=fat[y][i];
}
}
return fat[x][0];
}
int add_num(int k,int l,int r,int pos,int val)
{
if(!k) k=++size;
if(l==r)
{
tree[k].date+=val;
return k;
}
int mid=(l+r)/2;
if(pos<=mid) tree[k].lch=add_num(tree[k].lch,l,mid,pos,val);
else tree[k].rch=add_num(tree[k].rch,mid+1,r,pos,val);
tree[k].date=max(tree[tree[k].lch].date,tree[tree[k].rch].date);
return k;
}
void work(int l,int r,int num)
{
int f=lca(l,r);
fir[l]=add_num(fir[l],1,sum,num,1);
fir[r]=add_num(fir[r],1,sum,num,1);
fir[f]=add_num(fir[f],1,sum,num,-1);
if(fat[f][0]) fir[fat[f][0]]=add_num(fir[fat[f][0]],1,sum,num,-1);
return;
}
int merge(int x,int y,int l,int r)
{
tree[0].date=-0x7fffffff;
if(!x||!y) return x+y;
if(l==r)
{
tree[x].date+=tree[y].date;
return x;
}
int mid=(l+r)/2;
if(l<=mid) tree[x].lch=merge(tree[x].lch,tree[y].lch,l,mid);
if(mid+1<=r) tree[x].rch=merge(tree[x].rch,tree[y].rch,mid+1,r);
tree[x].date=max(tree[tree[x].lch].date,tree[tree[x].rch].date);
// cout<<l<<' '<<r<<" "<<tree[x].lch<<' '<<tree[x].rch<<" "<<tree[tree[x].lch].date<<' '<<tree[tree[x].rch].date<<" "<<tree[x].date<<endl;
return x;
}
int ask(int x,int l,int r)
{
if(l==r) return l;
int mid=(l+r)/2;
if(tree[tree[x].lch].date<=0&&tree[tree[x].rch].date<=0) return 0;
if(tree[x].lch&&tree[tree[x].lch].date>tree[tree[x].rch].date)
return ask(tree[x].lch,l,mid);
else if(tree[x].lch&&tree[tree[x].lch].date==tree[tree[x].rch].date)
return ask(tree[x].lch,l,mid);
else if(tree[x].rch&&tree[tree[x].lch].date<tree[tree[x].rch].date)
return ask(tree[x].rch,mid+1,r);
else return 0;
}
int aaa(int x,int l,int r,int num)
{
if(!x) return 0;
if(l==r) return tree[x].date;
int mid=(l+r)/2;
if(num<=mid) return aaa(tree[x].lch,l,mid,num);
else return aaa(tree[x].rch,mid+1,r,num);
}
void dfs_re(int x)
{
vis[x]=1;
for(Reg int i=las[x];i;i=lian[i].next)
{
if(!vis[lian[i].ed])
{
dfs_re(lian[i].ed);
fir[x]=merge(fir[x],fir[lian[i].ed],1,sum);
}
}
ans[x]=ask(fir[x],1,sum);
// cout<<x<<" ";
// for(Reg int i=1;i<=sum;++i)
// {
// printf("%d ",aaa(fir[x],1,sum,i));
// }
// cout<<endl;
return;
}
int main()
{
scanf("%d%d",&n,&m);
tree[0].date=-0x7fffffff;
for(Reg int i=1,x,y;i<=n-1;++i)
{
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
ins[1]=1; dfs(1);
for(Reg int i=1,x,y,z;i<=m;++i)
{
scanf("%d%d%d",&que1[i],&que2[i],&que3[i]);
lss[i]=que3[i];
}
sort(lss+1,lss+m+1,less<int>());
sum=unique(lss+1,lss+m+1)-lss-1;
for(Reg int i=1;i<=m;++i) que3[i]=lower_bound(lss+1,lss+m+1,que3[i])-lss;
for(Reg int i=1;i<=m;++i) work(que1[i],que2[i],que3[i]);
memset(vis,0,sizeof(vis));
dfs_re(1);
for(Reg int i=1;i<=n;++i) printf("%d\n",lss[ans[i]]);
return 0;
}
$AC$代码($AC$)


#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define Reg register
using namespace std;
int n,m,tot,sum,size,fir[100050],las[100050],vis[100050],fat[100050][25],ins[100050];
int que1[100050],que2[100050],que3[100050],lss[100050],ans[100050];
struct Tu {int st,ed,val,next;} lian[200050];
struct Tree {int lch,rch,date;} tree[8000050];
void add(int x,int y)
{
lian[++tot].st=x;
lian[tot].ed=y;
lian[tot].next=las[x];
las[x]=tot;
return;
}
void dfs(int x)
{
vis[x]=1;
for(Reg int j=1;j<=20;++j)
fat[x][j]=fat[fat[x][j-1]][j-1];
for(Reg int i=las[x];i;i=lian[i].next)
{
if(!vis[lian[i].ed])
{
fat[lian[i].ed][0]=x;
ins[lian[i].ed]=ins[x]+1;
dfs(lian[i].ed);
}
}
return;
}
int lca(int x,int y)
{
if(ins[x]<ins[y]) swap(x,y);
if(ins[x]!=ins[y])
{
for(Reg int i=20;i>=0;--i)
if(ins[fat[x][i]]>ins[y]) x=fat[x][i];
if(x==y) return x;
x=fat[x][0];
if(x==y) return x;
}
if(x==y) return x;
for(Reg int i=20;i>=0;--i)
{
if(fat[x][i]!=fat[y][i])
{
x=fat[x][i];
y=fat[y][i];
}
}
return fat[x][0];
}
int add_num(int k,int l,int r,int pos,int val)
{
if(!k) k=++size;
if(l==r)
{
tree[k].date+=val;
return k;
}
int mid=(l+r)/2;
if(pos<=mid) tree[k].lch=add_num(tree[k].lch,l,mid,pos,val);
else tree[k].rch=add_num(tree[k].rch,mid+1,r,pos,val);
tree[k].date=max(tree[tree[k].lch].date,tree[tree[k].rch].date);
return k;
}
void work(int l,int r,int num)
{
int f=lca(l,r);
fir[l]=add_num(fir[l],1,sum,num,1);
fir[r]=add_num(fir[r],1,sum,num,1);
fir[f]=add_num(fir[f],1,sum,num,-1);
if(fat[f][0]) fir[fat[f][0]]=add_num(fir[fat[f][0]],1,sum,num,-1);
return;
}
int merge(int x,int y,int l,int r)
{
tree[0].date=-0x7fffffff;
if(!x||!y) return x+y;
if(l==r)
{
tree[x].date+=tree[y].date;
return x;
}
int mid=(l+r)/2;
if(l<=mid) tree[x].lch=merge(tree[x].lch,tree[y].lch,l,mid);
if(mid+1<=r) tree[x].rch=merge(tree[x].rch,tree[y].rch,mid+1,r);
tree[x].date=max(tree[tree[x].lch].date,tree[tree[x].rch].date);
// cout<<l<<' '<<r<<" "<<tree[x].lch<<' '<<tree[x].rch<<" "<<tree[tree[x].lch].date<<' '<<tree[tree[x].rch].date<<" "<<tree[x].date<<endl;
return x;
}
int ask(int x,int l,int r)
{
if(l==r) return l;
int mid=(l+r)/2;
if(tree[tree[x].lch].date<=0&&tree[tree[x].rch].date<=0) return 0;
if(tree[x].lch&&tree[tree[x].lch].date>tree[tree[x].rch].date)
return ask(tree[x].lch,l,mid);
else if(tree[x].lch&&tree[tree[x].lch].date==tree[tree[x].rch].date)
return ask(tree[x].lch,l,mid);
else if(tree[x].rch&&tree[tree[x].lch].date<tree[tree[x].rch].date)
return ask(tree[x].rch,mid+1,r);
else return 0;
}
int aaa(int x,int l,int r,int num)
{
if(!x) return 0;
if(l==r) return tree[x].date;
int mid=(l+r)/2;
if(num<=mid) return aaa(tree[x].lch,l,mid,num);
else return aaa(tree[x].rch,mid+1,r,num);
}
void dfs_re(int x)
{
vis[x]=1;
for(Reg int i=las[x];i;i=lian[i].next)
{
if(!vis[lian[i].ed])
{
dfs_re(lian[i].ed);
fir[x]=merge(fir[x],fir[lian[i].ed],1,sum);
}
}
ans[x]=ask(fir[x],1,sum);
return;
}
int main()
{
scanf("%d%d",&n,&m);
tree[0].date=-0x7fffffff;
for(Reg int i=1,x,y;i<=n-1;++i)
{
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
ins[1]=1; dfs(1);
for(Reg int i=1,x,y,z;i<=m;++i)
{
scanf("%d%d%d",&que1[i],&que2[i],&que3[i]);
lss[i]=que3[i];
}
sort(lss+1,lss+m+1,less<int>());
sum=unique(lss+1,lss+m+1)-lss-1;
for(Reg int i=1;i<=m;++i) que3[i]=lower_bound(lss+1,lss+sum+1,que3[i])-lss;
for(Reg int i=1;i<=m;++i) work(que1[i],que2[i],que3[i]);
memset(vis,0,sizeof(vis));
dfs_re(1);
for(Reg int i=1;i<=n;++i) printf("%d\n",lss[ans[i]]);
return 0;
}
这个题就尴尬了,离散化时的$lower_bound$函数里写错了一个变量,导致改了这个题一个下午。。
总结
考试开始时先看的$T1$,发现$T1$就是个板子。。。
然后花了$20$分钟打了$T1$,考完试发现自己拿了$40$分,程序中一个地方写错了。
溜了一眼$T2$,发现$T2$是个$DP$题,也没什么思路,就跳过了。
后面基本上都在打$T3$,$T3$是个数据结构题,感觉我的线段树还是比较熟练的,但是调代码就恶心了。。。
打$T3$用了一个小时,调这道题基本上也用了一个小时,最后还没调过来,考完试才发现当时没调离散化,有$1$个变量打错了。
总之,调代码是个恶心的活。。。但是调完代码如果过了就会非常愉悦。。。
还有就是板子要记熟,不要考试时因为这个吃亏。