题目链接:https://www.dotcpp.com/oj/problem1822.html
题目描述
作为 drd 送的生日礼物,atm 最近得到了一个俄罗斯娃娃。他对这个俄罗斯娃娃的构造很感兴趣。
俄罗斯娃娃是一层一层套起来的。假设:一个大小为 x 的俄罗斯娃娃里面可能会放任意多个大小小于 x 的俄罗斯娃娃(而市场上的套娃一般大娃里只能放一个小娃)。
drd 告诉 atm ,这个俄罗斯娃娃是由 n 个小娃娃组成的,它们的大小各不相同。 我们把这些小娃娃的大小从小到大依次记为 1 到 n 。
如果 atm 想观赏大小为 k 的小娃娃,他会先看这个小娃娃是否已经在桌子上了。 如果已经在桌子上,那么他就可以观赏了。否则他就打开桌子上某一个俄罗斯娃娃,将它套住的所有的小娃娃拿出来,摆在桌子上。
一开始桌子上只有 drd 送的大小为 n 的娃娃。注意,他只会将其中所有小娃娃拿出来,如果小娃娃里面还套着另外的小娃娃,他是不会将这些更里层的这些小娃娃拿出来的。
而且 atm 天生具有最优化的强迫症。他会最小化他所需要打开的娃娃的数目。
atm 是一个怪人。有时候他只想知道观看大小为 x 的娃娃时需要打开多少个娃娃(但并不去打开);有时候听 drd 说某个娃娃特别漂亮,于是他会打开看。现在请你输出他每次需要打开多少个娃娃。
【输入格式】
第一行两个数 n m ,表示娃娃的数目以及 atm 想看的娃娃的数目。
接下来 n - 1 行,每行两个数 u v,表示大小为 u 的娃娃里面套着一个大小为 v 的娃娃。保证 u > v 。
接下来 m 行,每行形如:
P x :表示 atm 一定要看到大小为 x 的娃娃;
Q x :表示 atm 只想知道为了看大小为 x 的娃娃,他需要打开多少个娃娃,但实际上并不打开他们。
【输出格式】
输出 m 行。对应输入中P操作或Q操作需要打开(或假想打开)多少个俄罗斯娃娃。
【样例输入】
5 5
5 3
5 4
3 2
3 1
Q 1
Q 4
P 2
Q 1
Q 4
【样例输出】
2
1
2
0
0
【数据范围】
对于 30% 的数据:n, m <= 1000
对于 100% 的数据:n, m <= 100000
题解:首先说一下,这个代码不对,但我绝对思路没啥问题,感觉是数据问题,emmm,思路就是,先跑一遍dfs序,如果是拆的话,就直接先递归到分支的根节点,然后在扫下来,对应的每一个分支相应的减一,因为他们的父辈减少了,首先这样是不会超时的,因为每个点只会处理一次,然后就是线段树区间更新单点查询,看了数据了,很大,没法自己算,和某些结果要么一样,要么差一,感觉还是数据有点问题
别粘代码,别粘代码!!!!某些oj过不了
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
struct node{
int to,nex;
}e[N*2];
struct node1{
int l,r;
int laz;
}tree[N<<2];
int head[N],len;
int n,m;
int f[N],ans[N];
int in[N],out[N],cnt;
int p[N];
void add(int x,int y)
{
e[len].to=y;
e[len].nex=head[x];
head[x]=len++;
}
void dfs(int u)
{
in[u]=++cnt;
p[cnt]=u;
int to;
for(int i=head[u];i!=-1;i=e[i].nex)
{
to=e[i].to;
ans[to]=ans[u]+1;
dfs(to);
}
out[u]=cnt;
}
void build(int l,int r,int cur)
{
tree[cur].l=l;
tree[cur].r=r;
tree[cur].laz=0;
if(l==r)
{
tree[cur].laz=ans[p[l]];
return;
}
int mid=(r+l)>>1;
build(l,mid,cur<<1);
build(mid+1,r,cur<<1|1);
}
void pushdown(int cur)
{
if(tree[cur].laz<0)
{
tree[cur<<1].laz+=tree[cur].laz;
tree[cur<<1|1].laz+=tree[cur].laz;
tree[cur].laz=0;
}
}
void update(int pl,int pr,int cur,int val)
{
if(pl<=tree[cur].l && tree[cur].r<=pr)
{
tree[cur].laz+=val;
return;
}
pushdown(cur);
if(pl<=tree[cur<<1].r) update(pl,pr,cur<<1,val);
if(pr>=tree[cur<<1|1].l) update(pl,pr,cur<<1|1,val);
}
int query(int pos,int cur)
{
if(tree[cur].l==tree[cur].r)
{
return tree[cur].laz;
}
pushdown(cur);
if(pos<=tree[cur<<1].r) return query(pos,cur<<1);
else return query(pos,cur<<1|1);
}
int tt[N];
int main()
{
int x,y;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)head[i]=-1;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
f[y]=x;
}
for(int i=1;i<=n;i++)
{
if(f[i]==0)
{
ans[i]=0;
dfs(i);
break;
}
}
build(1,n,1);
char op[2];
int tmp;
int l;
while(m--)
{
scanf("%s%d",op,&x);
if(op[0]=='Q')
{
printf("%d\n",query(in[x],1));
}
else
{
printf("%d\n",query(in[x],1));
l=0;
while(f[x]!=0)
{
tt[++l]=f[x];
x=f[x];
}
while(l)
{
out[tt[l]]=in[tt[l]];
for(int i=head[tt[l]];i!=-1;i=e[i].nex)
{
y=e[i].to;
f[y]=0;
// cout<<y<<" "<<in[y]<<" *** "<<out[y]<<endl;
update(in[y],out[y],1,-1);
}
l--;
}
}
}
return 0;
}