解题报告
这道题应该是NOIP近3年来最难的一道题了(2015寻找道路&2014解方程表示不服)。
细思极恐……这两年最难的两道题目尽然都要用LCA。所以今年?
树链剖分?LCT?什么东西,能吃吗?
这道题的原数据有一些奇奇怪怪的限制,可能是你考试时骗分的灵感,但也可能是……这道题正解的提示(反正我从来没注意过)。
声明:以下的数据分析不是我这个蒟蒻分析的出来的,copy了ZigZagK的思路。
如果是图是一条链,那么只有在
x+w[x] 或x−w[x] 时才能被观察员发现。
S=1,T=1 说明S和T其实需要分开来处理
怎么分开?可以考虑分成两条直链(没有拐弯)
1.
对于
2.
所以,对于一个点x我们只要分别找出有多少个任务满足
但是有没有注意
综上,这道题其实没有蕴含什么高级算法,也就一个LCA,但其思维复杂度,足以给那些高级算法和高级数据结构学傻的人敲了一记警钟(对我这种蒟蒻而言就是末日来了,虽然我没有学傻,因为我根本学不进去啊)
复杂度:
时间:
空间:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 300005
#define maxe 600005
using namespace std;
int n,m,tot,len,son[maxe],nxt[maxe],lnk[maxn],dep[maxn],fa[maxn][20],w[maxn],s[maxn],t[maxn],la[maxn],ans[maxn],ha[1000005],hb[1000005];
struct data{
int tot,son[maxn],nxt[maxn],lnk[maxn];
void add(int x,int y){
son[++tot]=y; nxt[tot]=lnk[x]; lnk[x]=tot;
}
}A,B,C,D;
inline char nc(){
static char buf[100000],*pa=buf,*pb=buf;
return pa==pb&&(pb=(pa=buf)+fread(buf,1,100000,stdin),pa==pb)?EOF:*pa++;
}
inline void readi(int &x){
x=0; char ch=nc();
while ('0'>ch||ch>'9') ch=nc();
while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=nc();}
}
void _add(int x,int y){
son[++tot]=y; nxt[tot]=lnk[x]; lnk[x]=tot;
}
void _dfs(int x,int dad){
for (int j=lnk[x];j;j=nxt[j])
if (son[j]!=dad) {dep[son[j]]=dep[x]+1; _dfs(son[j],x); fa[son[j]][0]=x;}
}
void _init(){
freopen("running.in","r",stdin);
freopen("running.out","w",stdout);
readi(n); readi(m);
for (int i=1,x,y;i<n;i++){
readi(x); readi(y); _add(x,y); _add(y,x);
}
for (int i=1;i<=n;i++) readi(w[i]);
dep[1]=1; _dfs(1,-1); len=log2(n);
for (int j=1;j<20;j++)
for (int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1];
}
int _LCA(int x,int y){
if (dep[x]<dep[y]) swap(x,y);
for (int j=len;j>=0&&dep[x]>dep[y];j--) if (dep[fa[x][j]]>=dep[y]) x=fa[x][j];
if (x==y) return x;
for (int j=len;j>=0;j--) if (fa[x][j]!=fa[y][j]) {x=fa[x][j]; y=fa[y][j];}
return fa[x][0];
}
void _count(int x,int dad){
int lsta=ha[dep[x]+w[x]+maxn],lstb=hb[dep[x]-w[x]+maxn];
for (int j=lnk[x];j;j=nxt[j])
if (son[j]!=dad) _count(son[j],x);
for (int j=A.lnk[x];j;j=A.nxt[j]) ha[A.son[j]+maxn]++;
for (int j=B.lnk[x];j;j=B.nxt[j]) hb[B.son[j]+maxn]++;
ans[x]+=ha[dep[x]+w[x]+maxn]-lsta+hb[dep[x]-w[x]+maxn]-lstb;
for (int j=C.lnk[x];j;j=C.nxt[j]) ha[C.son[j]+maxn]--;
for (int j=D.lnk[x];j;j=D.nxt[j]) hb[D.son[j]+maxn]--;
}
void _solve(){
memset(ha,0,sizeof(ha));
memset(hb,0,sizeof(hb));
memset(ans,0,sizeof(ans));
for (int i=1;i<=m;i++){
readi(s[i]); readi(t[i]); la[i]=_LCA(s[i],t[i]); int dis=dep[s[i]]+dep[t[i]]-(dep[la[i]]<<1);
A.add(s[i],dep[s[i]]); B.add(t[i],dep[t[i]]-dis); C.add(la[i],dep[s[i]]); D.add(la[i],dep[t[i]]-dis);
}
_count(1,-1);
for (int i=1;i<=m;i++) if (dep[s[i]]-dep[la[i]]==w[la[i]]) ans[la[i]]--;
for (int i=1;i<n;i++) printf("%d ",ans[i]); printf("%d",ans[n]);
}
int main()
{
_init();
_solve();
return 0;
}