JZOJ3234 阴阳
来源:互联网 发布:婚纱电子相册制作软件 编辑:程序博客网 时间:2024/04/28 18:43
题目描述
Farmer John 正在在计划自己的农场漫步。他的农场的结构就像一棵树:农场有N个谷仓(1<= N <=100,000),分别由N-1条路链接。这样,他便可以通过这些谷仓间的道路遍及各个谷仓。Farmer John想要选择一条路线:这条路线的起点和终点分别为农场中两个不同的谷仓,这条路线不能重复经过一条边两次。Farmer John担心这条路径可能会偏长,所以他想在路线上寻找一个休息点(当然这个休息点不能为起点或者终点)。
每条边的两旁都是牛群,要么是Charcolais(白毛),要么是Angus(黑毛)。Farmer John是一个聪明人,所以他想要在他通过小路的同时平衡小路两侧阴阳的力量。他要选择一条路径使得他从起点到休息站,和从休息站到终点这两段路上都满足路两边的Charcolais牛群和Angus牛群总数量相同。
Farmer John好奇他能找到多少条如上所述的平衡的路径。我们认为,当且仅当两条路线的边的集合不同时,这两条路径才被认为是不同的,否则认为是相同的路线。就算路线上有多个有效的“休息站”的位置能使路线平衡,我们也只记为一条路线。
请帮助计算有多少条不同的平衡路线。
分析
这题我一开始就看错了···关键是一条路径上要找到一个分割点,然后两边的路都要是两种牛数量相同的。
好了分析一下吧,我们可以首先把不同牛看成是-1和1的权值。然后要找一条路径,和一个割点,使两端平衡嘛。我们先定个根吧,当根为rx时,我们从根上发射出size_rx条路径,我们称为分路径。现在我们要干的就是配对了。这道题可以直接开个桶做,两条路径权值加起来等于0,就有可能在答案中。那么现在问题来了,怎么样的路径才是合法的呢?
我们先考虑分路径。只要分路径上有一个点的权值是和端点的一样的,那么这条分路径就是有割点的了。
我们知道,由两条分路径合起来的路径,只要有一条是有割点的,这条路就合法了,淡然两个都有割点更不用说。所以就可以统计了。还有一些特殊情况,这个就不说了。
看看时间复杂度吧。对于一个子树,处理必须经过他路径的复杂度是size_rx的,所以就可以点分治了。N log N解决问题。
代码
#include<cstdio>#include<iostream>#include<algorithm>using namespace std;typedef long long ll;const int S=100005;const int N=500005;struct rec{ int sig,cnt;//cnt equal pos}buc[N*2][2],tr[N];int dis[N],first[N*2],next[N*2],b[N*2],pd[N],c[N*2],st[N],en[N],i,x,y,t,n,t1,tt,ttt,t2,col,vis[N],f[N],cnt[N],up[N],go[N];ll ans;int cr(int x,int y,int t){ ttt++; b[ttt]=y; c[ttt]=(t==1)?1:-1; next[ttt]=first[x]; first[x]=ttt;}int dfs(int x,int y){ tt++; tr[tt].cnt=dis[x]; if (pd[dis[x]]!=0) tr[tt].sig=1; else tr[tt].sig=0; if (pd[dis[x]]==0) pd[dis[x]]=x; for(int p=first[x];p;p=next[p]) { if(b[p]!=y&&!vis[b[p]]) { dis[b[p]]=dis[x]+c[p]; dfs(b[p],x); } } if (pd[dis[x]]==x) pd[dis[x]]=0;}int thr(int x,int y){ cnt[x]=1; for (int p=first[x];p;p=next[p]) { if (b[p]!=y&&!vis[b[p]]) { thr(b[p],x); cnt[x]+=cnt[b[p]]; } }}int find(int x,int y){ int ret=x,tmp; f[x]=up[x]; for(int p=first[x];p;p=next[p]) if (b[p]!=y&&!vis[b[p]]) f[x]=max(cnt[b[p]],f[x]); for(int p=first[x];p;p=next[p]) if (b[p]!=y&&!vis[b[p]]) { up[b[p]]=up[x]+cnt[x]-cnt[b[p]]; tmp=find(b[p],x); if (f[ret]>f[tmp]) ret=tmp; } return ret;}ll getans(){ ll ret=0; for(int i=1;i<=t2;i++) for(int j=st[i];j<=en[i];j++) { if (buc[tr[j].cnt+S][tr[j].sig].sig!=col) { buc[tr[j].cnt+S][tr[j].sig].sig=col; buc[tr[j].cnt+S][tr[j].sig].cnt=1; } else buc[tr[j].cnt+S][tr[j].sig].cnt++; } for(int i=1;i<=t2;i++) { for(int j=st[i];j<=en[i];j++) buc[tr[j].cnt+S][tr[j].sig].cnt--; for(int j=st[i];j<=en[i];j++) { if (tr[j].cnt==0&&tr[j].sig==1) ret++; if (buc[-tr[j].cnt+S][1].sig==col) ret+=buc[-tr[j].cnt+S][1].cnt; if ((tr[j].sig==1||tr[j].cnt==0)&&(buc[-tr[j].cnt+S][0].sig==col)) ret+=buc[-tr[j].cnt+S][0].cnt; } } return ret;}int solve(int x,int y){ //printf("%d\n",&x); vis[x]=1; tt=0; t2=0; for(int p=first[x];p;p=next[p]) { if (vis[b[p]]==0) { //pd[0]=x; t2++; st[t2]=en[t2-1]+1; dis[b[p]]=dis[x]+c[p]; dfs(b[p],x); en[t2]=tt; //pd[0]=0; } } col++; ans+=getans(); for(int p=first[x];p;p=next[p]) { if (vis[b[p]]==0) { thr(b[p],x); t1++; up[b[p]]=0; go[t1]=find(b[p],x); dis[go[t1]]=0; solve(go[t1],x); } }}int main(){ freopen("angus.in","r",stdin); freopen("angus.out","w",stdout); scanf("%d",&n); for(i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&t); cr(x,y,t); cr(y,x,t); } thr(1,0); t1++; go[1]=find(1,0); dis[go[1]]=0; solve(go[1],0); printf("%lld",ans);}
反思
这道题是第一道用GDB调试的题目,还不是很熟,要多练。
我读程序调试能力还是不强,可能是懒,需要改正,因为一旦想通了,就能节省很多时间。
打代码的时候有些分心,这样不好。
- JZOJ3234 阴阳
- 阴阳
- 阴阳
- 阴阳
- 紫极论阴阳
- 阴阳鱼
- 阴阳心态
- 阴阳合二为一称作一日
- 阴阳两界
- 阴阳怕懵懂吗?
- 阴阳怕懵懂吗?
- 明辨阴阳,合理修炼
- 阴阳字进度条
- 阴阳 详细题解+代码
- 启动 阴阳鱼 计划
- 关于阴阳谜题
- 五脏六腑怎么分阴阳
- 应用阴阳线形态分析
- 多线程
- 设计模式-单一职责原则
- 在IOS 8 iOS 9 中使用CoreLocation 获取地理位置
- SWIFT中获取当前经伟度
- 根据经纬度获取地点名称
- JZOJ3234 阴阳
- Java SE7新特性之try-with-resources语句
- Codeforces 635E Package Delivery【贪心】
- 与Service交互的三种方式
- kafka文档(3)---- 配置选项翻译
- java常用正则表达式
- 服务器的默认编码配置之tomcat及maven的配置
- Java工程师成神之路~
- POJ 3126 Prime Path