直接用f数组保存每个点的父节点,vis数组保存这个点的更新时间,num数组保存任务
每次更新时只需要更新一个点的num和vis
再查询的时候通过vis将这个点和它所有上级的num更新为最新,然后输出num
这样做如果碰到极端数据时间复杂度很高,不过平均来说还是O(mlogn),轻松AC
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
using namespace std;
typedef long long ll;
const int maxn=50000+10; //数组大小
int vis[maxn];
int f[maxn];
int num[maxn];
int n,m,a,b;
char c[5];
int find(int u)
{
if(f[u]==-1)
{
return vis[u];
}
int t=find(f[u]);
if(t>vis[u]) //有最新状态
{
vis[u]=t;
num[u]=num[f[u]];
}
return vis[u];
}
int main()
{
//freopen("/home/zlwang/test.txt","r",stdin);
int T,kase=0;
scanf("%d",&T);
while(T--)
{
memset(f,-1,sizeof(f));
memset(num,-1,sizeof(num));
memset(vis,0,sizeof(vis));
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
f[a]=b;
}
printf("Case #%d:\n",++kase);
scanf("%d",&m);
int cnt=0;
for(int i=0;i<m;i++)
{
scanf("%s",c);
if(c[0]=='C')
{
scanf("%d",&a);
find(a);
printf("%d\n",num[a]);
}
else if(c[0]=='T')
{
scanf("%d%d",&a,&b);
num[a]=b;
vis[a]=++cnt;
}
}
}
return 0;
}
下面是dfs时间戳将多叉树转换为线段树,然后用线段树成段更新的做法
用dfs先序遍历树,可以将每个点和其子节点的区间保存为l~r,就可以使用线段树区间更新来更新整个树
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
const int maxn=50000+5; //数组大小
int lazy[maxn<<2]; //懒惰标记
int sum[maxn<<2];
bool vis[maxn];
int l[maxn],r[maxn];
vector<int> g[maxn];
int cnt,n,m,a,b;
char c[5];
void dfs(int u)
{
l[u]=++cnt;
for(int i=0;i<g[u].size();i++)
dfs(g[u][i]);
r[u]=cnt;
}
void PushDown(int rt,int m) //向下更新
{
if(lazy[rt]!=-1) //懒惰标记,这里的语句根据更新函数而变
{
lazy[rt<<1]=lazy[rt];
lazy[rt<<1|1]=lazy[rt];
sum[rt<<1]=lazy[rt];
sum[rt<<1|1]=lazy[rt];
lazy[rt]=-1;
}
}
void build(int l,int r,int rt) //建树
{
sum[rt]=-1;
lazy[rt]=-1;
if(l==r)
{
//sum[rt]=-1;
return;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
}
void update(int L,int R,int c,int l,int r,int rt) //将L~R区间改为c,可以根据需要修改更新函数
{
if(L<=l&&R>=r)
{
lazy[rt]=c;
sum[rt]=c;
return;
}
PushDown(rt,r-l+1);
int m=(l+r)>>1;
if(L<=m) update(L,R,c,l,m,rt<<1);
if(m<R) update(L,R,c,m+1,r,rt<<1|1);
}
int query(int L,int R,int l,int r,int rt) //查询L~R
{
if(L<=l&&R>=r)
return sum[rt];
PushDown(rt,r-l+1);
int m=(l+r)>>1;
if(L<=m) return query(L,R,l,m,rt<<1);
if(m<R) return query(L,R,m+1,r,rt<<1|1);
}
int main()
{
//freopen("/home/zlwang/test.txt","r",stdin);
int T,kase=0;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
g[i].clear();
memset(vis,false,sizeof(vis));
for(int i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
g[b].push_back(a);
vis[a]=true;
}
int rt=0;
for(int i=1;i<=n;i++)
if(!vis[i])
{
rt=i;
break;
}
cnt=0;
dfs(rt);
build(1,n,1);
printf("Case #%d:\n",++kase);
scanf("%d",&m);
int cnt=0;
for(int i=0;i<m;i++)
{
scanf("%s",c);
if(c[0]=='C')
{
scanf("%d",&a);
printf("%d\n",query(l[a],l[a],1,n,1));
}
else if(c[0]=='T')
{
scanf("%d%d",&a,&b);
update(l[a],r[a],b,1,n,1);
}
}
}
return 0;
}