【BZOJ】【3697】采药人的路径&【3127】【USACO2013 Open】Yin and Yang
2015-06-17 11:34
288 查看
点分治
Orz hzwer倒是比较好想到点分治……然而在方案统计这里,我犯了两个错误……
1.我比较傻逼的想的是:通过儿子来更新父亲,也就是统计以x为根的子树中xxxx的路径有多少条……这样转移。
然而这实在是太傻逼了,黄学长教做人:从父亲来更新儿子,走到一个节点直接更新路径的统计数,反正我们要的是【经过root的xx路径的数量】
所以可以一遍dfs直接搞出来……
2.统计方案的方式也想错了……我只考虑了以root作为中转站的路径,然而经过root的路径中,并不只有这种路径是合法的……中转站在途中某个点的也可以QwQ
另外感觉黄学长记录[-d,d]的姿势很神啊……直接数组开大一倍,然后转成[n-d,n+d]……
其他的……套模板呗- -
//BZOJ 3697 #include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define rep(i,n) for(int i=0;i<n;++i) #define F(i,j,n) for(int i=j;i<=n;++i) #define D(i,j,n) for(int i=j;i>=n;--i) #define pb push_back using namespace std; typedef long long LL; inline int getint(){ int r=1,v=0; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1; for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch; return r*v; } const int N=1e5+10; /*******************template********************/ int to[N<<1],nxt[N<<1],head ,cnt,v[N<<1]; void add(int x,int y,int z){ to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt; v[cnt]=z; to[++cnt]=x; nxt[cnt]=head[y]; head[y]=cnt; v[cnt]=z; } int n,rt,s ,h ,size,dep ,mxdeep; LL ans,g[N*2][2],f[N*2][2]; int t[N<<1],dis ; bool vis ; inline void getroot(int x,int fa){ s[x]=1; h[x]=0; for(int i=head[x];i;i=nxt[i]) if (to[i]!=fa && !vis[to[i]]){ getroot(to[i],x); s[x]+=s[to[i]]; h[x]=max(h[x],s[to[i]]); } h[x]=max(h[x],size-s[x]); if (h[x]<h[rt]) rt=x; } inline void dfs(int x,int fa){ mxdeep=max(mxdeep,dep[x]); if (t[dis[x]]) g[dis[x]][1]++; else g[dis[x]][0]++; t[dis[x]]++; for(int i=head[x];i;i=nxt[i]) if (!vis[to[i]] && to[i]!=fa){ dep[to[i]]=dep[x]+1; dis[to[i]]=dis[x]+v[i]; dfs(to[i],x); } t[dis[x]]--; } inline void getans(int x){ int mx=0; vis[x]=1; f [0]=1; for(int i=head[x];i;i=nxt[i]) if (!vis[to[i]]){ dis[to[i]]=n+v[i]; dep[to[i]]=1; mxdeep=1; dfs(to[i],x); mx=max(mx,mxdeep); ans+=(f [0]-1)*g [0]; F(j,-mxdeep,mxdeep) ans+=f[n-j][1]*g[n+j][1]+f[n-j][0]*g[n+j][1]+f[n-j][1]*g[n+j][0]; //f [0]+1的原因是要将x作为起点or终点的合法路径(g [1])统计进来 F(j,n-mxdeep,n+mxdeep) f[j][0]+=g[j][0], f[j][1]+=g[j][1], g[j][0]=g[j][1]=0; } F(i,n-mx,n+mx) f[i][0]=f[i][1]=0; //统计答案↑ for(int i=head[x];i;i=nxt[i]) if (!vis[to[i]]){ rt=0; size=s[to[i]]; getroot(to[i],x); getans(rt); } //继续分治↑ } int main(){ #ifndef ONLINE_JUDGE freopen("3697.in","r",stdin); freopen("3697.out","w",stdout); #endif n=getint(); F(i,2,n){ int x=getint(),y=getint(),z=getint(); if (!z) z--; add(x,y,z); } size=n; h[rt=0]=n+1; getroot(1,0); getans(rt); printf("%lld\n",ans); return 0; }
View Code
3697: 采药人的路径
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 252 Solved: 93
[Submit][Status][Discuss]
Description
采药人的药田是一个树状结构,每条路径上都种植着同种药材。采药人以自己对药材独到的见解,对每种药材进行了分类。大致分为两类,一种是阴性的,一种是阳性的。
采药人每天都要进行采药活动。他选择的路径是很有讲究的,他认为阴阳平衡是很重要的,所以他走的一定是两种药材数目相等的路径。采药工作是很辛苦的,所以
他希望他选出的路径中有一个可以作为休息站的节点(不包括起点和终点),满足起点到休息站和休息站到终点的路径也是阴阳平衡的。他想知道他一共可以选择多
少种不同的路径。
Input
第1行包含一个整数N。接下来N-1行,每行包含三个整数a_i、b_i和t_i,表示这条路上药材的类型。
Output
输出符合采药人要求的路径数目。Sample Input
71 2 0
3 1 1
2 4 0
5 2 0
6 3 1
5 7 1
Sample Output
1HINT
对于100%的数据,N ≤ 100,000。Source
[Submit][Status][Discuss]相关文章推荐
- windows下同时启动多个tomcat
- Hadoop集群搭建
- centos copy方式 eth0不见了问题解决
- linux 命令——32 gzip(转)
- linux下搭建cacti监控
- linux 文件系统之SSD
- Linux操作系统上安装Mysql数据库
- centos常用系统命令
- 继承PopWindows
- Linux操作系统上安装JDK
- 技术文章存档
- Tomcat源码编译
- linux命令 ——目录
- 在写一个嵌入式Linux构建的初级教程,先放上两篇,请大家拍拍转。
- linux 安装 nginx
- linux中五个常用查找命令
- linux 命令——31 /etc/group文件(转)
- 自定义Apache的404页面
- iptables 应用层过滤
- iptables基本用法