3631: [JLOI2014]松鼠的新家
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 2560 Solved: 1357
[Submit][Status][Discuss]Description
松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在“树”上。松鼠想邀请****前来参观,并且还指定一份参观指南,他希望**能够按照他的指南顺序,先去a1,再去a2,……,最后到an,去参观新家。可是这样会导致**重复走很多房间,懒惰的**不听地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。**是个馋家伙,立马就答应了。现在松鼠希望知道为了保证**有糖果吃,他需要在每一个房间各放至少多少个糖果。因为松鼠参观指南上的最后一个房间an是餐厅,餐厅里他准备了丰盛的大餐,所以当**在参观的最后到达餐厅时就不需要再拿糖果吃了。Input
第一行一个整数n,表示房间个数第二行n个整数,依次描述a1-an接下来n-1行,每行两个整数x,y,表示标号x和y的两个房间之间有树枝相连。Output
一共n行,第i行输出标号为i的房间至少需要放多少个糖果,才能让**有糖果吃。Sample Input
5
1 4 5 3 2
1 2
2 4
2 3
4 5
Sample Output
1
2
1
2
1
HINT
2<= n <=300000
题目大意:给定一棵n个节点的树和一个1~n的排列ai,对于每一个i,给从ai到ai+1的路径上除了起点以外的点都加上1,求每个点最终的值
题解:
看到题就感觉像树剖,于是就直接套板子上了。每次对于一条链来说,给左端点加上1,右端点的下一位减去1,最后做一个前缀和。注意每次是不给起点+1的,因此最后给除了a1以外的点全部-1就好了
代码:
1 #include<cmath> 2 #include<math.h> 3 #include<ctype.h> 4 #include<algorithm> 5 #include<bitset> 6 #include<cassert> 7 #include<cctype> 8 #include<cerrno> 9 #include<cfloat> 10 #include<ciso646> 11 #include<climits> 12 #include<clocale> 13 #include<complex> 14 #include<csetjmp> 15 #include<csignal> 16 #include<cstdarg> 17 #include<cstddef> 18 #include<cstdio> 19 #include<cstdlib> 20 #include<cstring> 21 #include<ctime> 22 #include<cwchar> 23 #include<cwctype> 24 #include<deque> 25 #include<exception> 26 #include<fstream> 27 #include<functional> 28 #include<iomanip> 29 #include<ios> 30 #include<iosfwd> 31 #include<iostream> 32 #include<istream> 33 #include<iterator> 34 #include<limits> 35 #include<list> 36 #include<locale> 37 #include<map> 38 #include<memory> 39 #include<new> 40 #include<numeric> 41 #include<ostream> 42 #include<queue> 43 #include<set> 44 #include<sstream> 45 #include<stack> 46 #include<stdexcept> 47 #include<streambuf> 48 #include<string> 49 #include<typeinfo> 50 #include<utility> 51 #include<valarray> 52 #include<vector> 53 #include<string.h> 54 #include<stdlib.h> 55 #include<stdio.h> 56 using namespace std; 57 58 typedef long long ll; 59 60 #define pb push_back 61 #define mp make_pair 62 #define x first 63 #define y second 64 65 const ll inf=2147483647; 66 67 // 68 69 ll read() 70 { 71 ll x=0,f=1; 72 char ch=getchar(); 73 while(ch<'0'||ch>'9') 74 { 75 if(ch=='-')f=-1; 76 ch=getchar(); 77 } 78 while(ch>='0'&&ch<='9') 79 { 80 x=x*10+ch-'0'; 81 ch=getchar(); 82 } 83 return x*f; 84 } 85 86 void print(ll x) 87 { 88 if(x<0)putchar('-'),x=-x; 89 short a[20]= {},sz=0; 90 while(x>0)a[sz++]=x%10,x/=10; 91 if(sz==0)putchar('0'); 92 for(ll i=sz-1; i>=0; i--)putchar('0'+a[i]); 93 } 94 95 const ll mod=1e9+7; 96 97 int n; 98 int a[333333]; 99 vector<int> adj[333333]; 100 101 int fa[333333]; 102 int dep[333333]; 103 int sz[333333]; 104 int son[333333]; 105 int tp[333333]; 106 int num[333333]; 107 int rnk[333333]; 108 int cnt; 109 110 void dfs1(int nw,int pa,int d){ 111 fa[nw]=pa; 112 dep[nw]=d; 113 sz[nw]=1; 114 for(int i=0;i<adj[nw].size();i++){ 115 int v=adj[nw][i]; 116 if(v==pa) continue; 117 dfs1(v,nw,d+1); 118 if(son[nw]==0 || sz[son[nw]]<sz[v]) son[nw]=v; 119 sz[nw]+=sz[v]; 120 } 121 } 122 123 void dfs2(int nw,int t){ 124 tp[nw]=t; 125 num[nw]=++cnt; 126 rnk[cnt]=nw; 127 128 if(son[nw]==0) return; 129 dfs2(son[nw],t); 130 131 for(int i=0;i<adj[nw].size();i++){ 132 int v=adj[nw][i]; 133 if(v==fa[nw] || v==son[nw]) continue; 134 dfs2(v,v); 135 } 136 } 137 138 int root; 139 void doit(){ 140 //树链剖分 141 root=a[1]; 142 dfs1(root,-1,0); 143 dfs2(root,root); 144 /* 145 for(int i=1;i<=cnt;i++) 146 cout<<rnk[i]<<' '; 147 cout<<endl;*/ 148 } 149 150 int ans[333333]; 151 152 inline void add(int a,int b){ 153 //cout<<a<<' '<<b<<endl; 154 if(a>b) swap(a,b); 155 ans[a]++; 156 ans[b+1]--; 157 } 158 159 void update_path(int x,int y){ 160 int fx=tp[x],fy=tp[y]; 161 while(fx!=fy){ 162 if(dep[fx]>=dep[fy]){ 163 add(num[fx],num[x]); 164 x=fa[fx]; 165 } 166 else{ 167 add(num[fy],num[y]); 168 y=fa[fy]; 169 } 170 fx=tp[x]; 171 fy=tp[y]; 172 } 173 add(num[x],num[y]); 174 } 175 176 int main(){ 177 //freopen("in","r",stdin); 178 n=read(); 179 for(int i=1;i<=n;i++) 180 a[i]=read(); 181 for(int i=1;i<n;i++){ 182 int a=read(),b=read(); 183 adj[a].pb(b);adj[b].pb(a); 184 } 185 186 doit(); 187 188 for(int i=1;i<n;i++){ 189 update_path(a[i],a[i+1]); 190 } 191 192 for(int i=1;i<=n;i++){ 193 ans[i]+=ans[i-1]; 194 } 195 for(int i=2;i<=n;i++) 196 ans[i]--; 197 198 for(int i=1;i<=n;i++){ 199 printf("%d\n",ans[num[i]]); 200 } 201 202 return 0; 203 } 204 205 /* 206 5 207 1 4 5 3 2 208 1 2 209 2 4 210 2 3 211 4 5 212 */
然后就发现自己做烦了。
我都想到了给左端点加1右端点减1了,就没想到树上也能这样做
每次操作,给两个端点都加上1,然后给他们的lca减去1,lca的父亲也减去1,然后在dfs一下,每个点的权值加上他的儿子们的权值。注意,输出时所有的点的权值-1,原因同上
代码:
1 #include<cmath> 2 #include<math.h> 3 #include<ctype.h> 4 #include<algorithm> 5 #include<bitset> 6 #include<cassert> 7 #include<cctype> 8 #include<cerrno> 9 #include<cfloat> 10 #include<ciso646> 11 #include<climits> 12 #include<clocale> 13 #include<complex> 14 #include<csetjmp> 15 #include<csignal> 16 #include<cstdarg> 17 #include<cstddef> 18 #include<cstdio> 19 #include<cstdlib> 20 #include<cstring> 21 #include<ctime> 22 #include<cwchar> 23 #include<cwctype> 24 #include<deque> 25 #include<exception> 26 #include<fstream> 27 #include<functional> 28 #include<iomanip> 29 #include<ios> 30 #include<iosfwd> 31 #include<iostream> 32 #include<istream> 33 #include<iterator> 34 #include<limits> 35 #include<list> 36 #include<locale> 37 #include<map> 38 #include<memory> 39 #include<new> 40 #include<numeric> 41 #include<ostream> 42 #include<queue> 43 #include<set> 44 #include<sstream> 45 #include<stack> 46 #include<stdexcept> 47 #include<streambuf> 48 #include<string> 49 #include<typeinfo> 50 #include<utility> 51 #include<valarray> 52 #include<vector> 53 #include<string.h> 54 #include<stdlib.h> 55 #include<stdio.h> 56 using namespace std; 57 58 typedef long long ll; 59 60 #define pb push_back 61 #define mp make_pair 62 #define x first 63 #define y second 64 65 const ll inf=2147483647; 66 67 // 68 69 ll read() 70 { 71 ll x=0,f=1; 72 char ch=getchar(); 73 while(ch<'0'||ch>'9') 74 { 75 if(ch=='-')f=-1; 76 ch=getchar(); 77 } 78 while(ch>='0'&&ch<='9') 79 { 80 x=x*10+ch-'0'; 81 ch=getchar(); 82 } 83 return x*f; 84 } 85 86 void print(ll x) 87 { 88 if(x<0)putchar('-'),x=-x; 89 short a[20]= {},sz=0; 90 while(x>0)a[sz++]=x%10,x/=10; 91 if(sz==0)putchar('0'); 92 for(ll i=sz-1; i>=0; i--)putchar('0'+a[i]); 93 } 94 95 const ll mod=1e9+7; 96 97 int fa[21][333333]; 98 int n; 99 int a[333333]; 100 vector<int> adj[333333]; 101 int tag[333333]; 102 int dep[333333]; 103 104 void dfs(int nw,int pa){ 105 // cout<<nw<<' '<<pa<<endl; 106 fa[0][nw]=pa; 107 for(int i=0;i<adj[nw].size();i++){ 108 int v=adj[nw][i]; 109 if(v==pa) continue; 110 dep[v]=dep[nw]+1; 111 dfs(v,nw); 112 } 113 } 114 115 inline int lca(int x,int y){ 116 if(x==y) return x; 117 if(dep[x]<dep[y]) swap(x,y); 118 for(int i=19;i>=0;i--){ 119 if(dep[fa[i][x]]>dep[y]) x=fa[i][x]; 120 } 121 if(dep[x]>dep[y]) x=fa[0][x]; 122 if(x==y) return x; 123 for(int i=19;i>=0;i--){ 124 if(fa[i][x]!=fa[i][y]) 125 x=fa[i][x],y=fa[i][y]; 126 } 127 return fa[0][x]; 128 } 129 130 void doit(int x,int y){ 131 int z=lca(x,y); 132 //cout<<x<<' '<<y<<' '<<z<<endl; 133 tag[x]++; 134 tag[y]++; 135 tag[z]--; 136 tag[fa[0][z]]--; 137 } 138 139 void pushup(int nw){ 140 for(int i=0;i<adj[nw].size();i++){ 141 int v=adj[nw][i]; 142 if(v==fa[0][nw]) continue; 143 pushup(v); 144 tag[nw]+=tag[v]; 145 } 146 } 147 148 void hahaha(){ 149 hahaha(); 150 } 151 152 int main(){ 153 //freopen("in","r",stdin); 154 //freopen("1","w",stdout); 155 n=read(); 156 for(int i=1;i<=n;i++) 157 a[i]=read(); 158 a[0]=a[1]; 159 160 for(int i=1;i<n;i++){ 161 int fr=read(),tt=read(); 162 adj[fr].pb(tt); 163 adj[tt].pb(fr); 164 } 165 adj[0].pb(a[1]); 166 167 dfs(0,0); 168 169 for(int i=1;i<=19;i++){ 170 for(int j=1;j<=n;j++){ 171 fa[i][j]=fa[i-1][fa[i-1][j]]; 172 } 173 } 174 175 for(int i=1;i<=n;i++) 176 doit(a[i-1],a[i]); 177 /* 178 for(int i=1;i<=n;i++) 179 printf("%d\n",tag[i]); 180 */ 181 pushup(0); 182 183 for(int i=1;i<=n;i++) 184 printf("%d\n",tag[i]-1); 185 186 return 0; 187 }