[HZOI 2016]tree—增强版
[HZOI 2016]tree—增强版
注意事项
为了体现增强版,题目限制和数据范围有所增强:
时间限制:1.5s
内存限制:128MB
对于15% 的数据,1<=N,Q<=1000.
对于35% 的数据,1<=N,Q<=10000.
对于50% 的数据,1<=N,Q<=100000,且数据均为官方数据.
对于100% 的数据,1<=N,Q<=1000000.
请注意常数因子对于程序运行的影响。
解题报告
原题数据水到不行= =
直接找父节点都能上榜= =
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 inline int read(){ 6 int sum(0); 7 char ch(getchar()); 8 for(;ch<'0'||ch>'9';ch=getchar()); 9 for(;ch>='0'&&ch<='9';sum=sum*10+(ch^48),ch=getchar()); 10 return sum; 11 } 12 struct edge{ 13 int e; 14 edge *n; 15 edge():e(0),n(NULL){} 16 }a[200005],*pre[100005]; 17 int tot; 18 inline void insert(int s,int e){ 19 a[++tot].e=e; 20 a[tot].n=pre[s]; 21 pre[s]=&a[tot]; 22 } 23 int n,q; 24 char op[2]; 25 bool bj[100005]; 26 int fa[100005]; 27 inline void dfs(int u){ 28 for(edge *i=pre[u];i;i=i->n){ 29 int e(i->e); 30 if(e!=fa[u]){ 31 fa[e]=u; 32 dfs(e); 33 } 34 } 35 } 36 inline int query(int u){ 37 while(!bj[u]) 38 u=fa[u]; 39 return u; 40 } 41 inline int gg(){ 42 freopen("heoi2016_tree.in","r",stdin); 43 freopen("heoi2016_tree.out","w",stdout); 44 memset(pre,NULL,sizeof(pre)); 45 n=read(),q=read(); 46 bj[1]=1; 47 for(int i=1;i<n;++i){ 48 int x(read()),y(read()); 49 insert(x,y),insert(y,x); 50 } 51 dfs(1); 52 while(q--){ 53 scanf("%s",op); 54 int x(read()); 55 if(op[0]=='Q') 56 printf("%d\n",query(x)); 57 else 58 bj[x]=1; 59 } 60 return 0; 61 } 62 int K(gg()); 63 int main(){;}
然而加强版数据真的不是闹着玩的= =
首先我们看,它是一个不断往上爬,直到爬到第一个有标记的点或者是根节点时才停止的过程,那么我们很容易想到树剖,从当前节点往上爬就好了
同时我们注意到,题目要求找离当前节点最近的被标记的祖先,所以我们只要去找深度最深的被标记的祖先即可,而由树链剖分中$dfs$序的性质可知,在同一条链上越深的节点,它的时间戳就越大,那么我们显然可以维护一颗最大值的线段树,假如该点被标记,就把它的时间戳加入线段树
剩下的就很好实现了
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstdlib> 5 using namespace std; 6 inline int read(){ 7 int sum=0; 8 char ch=getchar(); 9 for(;ch<'0'||ch>'9';ch=getchar()); 10 for(;ch>='0'&&ch<='9';sum=sum*10+(ch^48),ch=getchar()); 11 return sum; 12 } 13 struct edge{ 14 int e,n; 15 }a[1000005]; 16 int pre[1000005]; 17 int tot; 18 inline void insert(int s,int e){ 19 a[++tot].e=e; 20 a[tot].n=pre[s]; 21 pre[s]=tot; 22 } 23 int dep[1000005],fa[1000005],son[1000005],size[1000005]; 24 inline void dfs1(int u){ 25 size[u]=1,son[u]=0; 26 for(int i=pre[u];i!=-1;i=a[i].n){ 27 int e=a[i].e; 28 if(e!=fa[u]){ 29 fa[e]=u; 30 dep[e]=dep[u]+1; 31 dfs1(e); 32 size[u]+=size[e]; 33 if(size[e]>size[son[u]]) 34 son[u]=e; 35 } 36 } 37 } 38 int cnt; 39 int top[1000005],id[1000005],pos[1000005]; 40 inline void dfs2(int u,int rt){ 41 top[u]=rt; 42 id[u]=++cnt; 43 pos[cnt]=u; 44 if(son[u]) 45 dfs2(son[u],rt); 46 else 47 return; 48 for(int i=pre[u];i!=-1;i=a[i].n){ 49 int e=a[i].e; 50 if(e!=fa[u]&&e!=son[u]) 51 dfs2(e,e); 52 } 53 } 54 int mx[4000005]; 55 inline void pushup(int i){ 56 mx[i]=max(mx[i<<1],mx[i<<1|1]); 57 } 58 inline void update(int pos,int l,int r,int i){ 59 if(l==r){ 60 mx[i]=pos; 61 return; 62 } 63 int mid=l+r>>1; 64 if(pos<=mid) 65 update(pos,l,mid,i<<1); 66 else 67 update(pos,mid+1,r,i<<1|1); 68 pushup(i); 69 } 70 inline int query(int ll,int rr,int l,int r,int i){ 71 if(ll<=l&&r<=rr) 72 return mx[i]; 73 int mid=l+r>>1,ret=0; 74 if(ll<=mid) 75 ret=max(query(ll,rr,l,mid,i<<1),ret); 76 if(mid<rr) 77 ret=max(query(ll,rr,mid+1,r,i<<1|1),ret); 78 return ret; 79 } 80 int n,q; 81 char op[2]; 82 inline int ask(int x){ 83 int ret(1); 84 while(x){ 85 int tmp=query(id[top[x]],id[x],1,n,1); 86 if(tmp) 87 ret=dep[ret]>dep[pos[tmp]]?ret:pos[tmp]; 88 x=fa[top[x]]; 89 } 90 return ret; 91 } 92 int main(){ 93 int __size__ = 50 << 20; 94 char *__p__ = (char*)malloc(__size__) + __size__; 95 __asm__("movl %0, %%esp\n" :: "r"(__p__)); 96 freopen("tree++.in","r",stdin); 97 freopen("tree++.out","w",stdout); 98 memset(pre,-1,sizeof(pre)); 99 n=read(),q=read(); 100 for(int i=1;i<n;++i){ 101 int x=read(),y=read(); 102 insert(x,y); 103 } 104 dfs1(1); 105 dfs2(1,1); 106 int x; 107 update(id[1],1,n,1); 108 for(int i=0;i<q;++i){ 109 scanf("%s",op); 110 x=read(); 111 if(op[0]=='Q') 112 printf("%d\n",ask(x)); 113 else 114 update(id[x],1,n,1); 115 } 116 return 0; 117 }