【BZOJ 3697】采药人的路径

题目链接:

  TP

题解:

  调了好久233。

  大概想一想就是树分,然后考虑这样路径(u,v)的特征,以根节点(root)切开,u到root的阴阳差值,和v到root巧合互为相反数,然后考虑要有一个点可作为休息点,即u/v到root的路径中要有一点x与u/v到root的阴阳差值相同,然后维护一下就好。

  注意的是阴阳差为0的特判……写挂了调好久,对拍也不好写,真是恶心。

代码:

  

 #define Troy 11/23
#define inf 0x7fffffff #include <bits/stdc++.h> using namespace std; inline int read(){
int s=,k=;char ch=getchar();
while(ch<''|ch>'') ch=='-'?k=-:,ch=getchar();
while(ch>&ch<='') s=s*+(ch^),ch=getchar();
return s*k;
} const int N=1e5+; typedef long long ll; int n; struct edges{
int v,w;edges *last;
}edge[N<<],*head[N];int cnt; inline void push(int u,int v,int w){
edge[++cnt]=(edges){v,w,head[u]};head[u]=edge+cnt;
} int tot,root,heavy[N],size[N],top,num,T[N<<][],nT[N<<],pre[N<<]; ll ans,t[N<<][]; bool vis[N]; inline void dfs(int x,int fa){
size[x]=,heavy[x]=;
for(edges *i=head[x];i;i=i->last)if(!vis[i->v]&&i->v!=fa){
dfs(i->v,x);
heavy[x]=max(heavy[x],size[i->v]);
size[x]+=size[i->v];
}
heavy[x]=max(heavy[x],tot-size[x]);
if(top>heavy[x])
top=heavy[x],root=x;
} #define g(s) t[s+n]
#define G(s) T[s+n]
#define f(s) pre[s+n] inline void update(int x,int s,int fa){
bool a=f(s)>;
if(G(s)[a]!=num)
G(s)[a]=num,g(s)[a]=;
++g(s)[a];
++f(s);
for(edges *i=head[x];i;i=i->last)if(!vis[i->v]&&i->v!=fa)
update(i->v,s+(i->w?:-),x);
--f(s);
} inline void calc(int x,int s,int fa){
bool a=f(s)>;
++f(s);
if(G(s)[]==num)
ans+=g(s)[];
if(a&&G(s)[]==num){
ans+=g(s)[];
if(!s&&f(s)<=) ans-=g(s)[];
}
for(edges *i=head[x];i;i=i->last)if(!vis[i->v]&&i->v!=fa)
calc(i->v,s+(i->w?-:),x);
--f(s);
}
inline void solve(int x){
top=inf;
dfs(x,x);
vis[x=root]=true;
G()[]=++num;
g()[]=;
for(edges *i=head[x];i;i=i->last)if(!vis[i->v]){
calc(i->v,i->w?-:,x);
update(i->v,i->w?:-,x);
}
for(edges *i=head[x];i;i=i->last)if(!vis[i->v]){
tot=size[i->v];
solve(i->v);
}
} int main(){
n=read();
for(int i=,u,v,w;i^n;++i){
u=read(),v=read(),w=read();
push(u,v,w);
push(v,u,w);
}
tot=n;
f()=;
solve();
printf("%lld\n",ans);
}
上一篇:Inno Setup入门(三)——指定压缩方式


下一篇:s:textarea 标签不能改变大小的解决方案