【蒟蒻的点分治专题训练】----5道题题解
来源:互联网 发布:windows.old可以移动 编辑:程序博客网 时间:2024/06/09 21:29
附题:
poj1741,hdu4812,codeforces161D,bzoj3697,bzoj2152
先来一波总结:
好好做了这几道题之后,发现树上的点分治几乎可以说是模板题,每道题改变的地方都只有处理 过当前子树根节点的路径,求重心,求距离几乎都没有什么太大改变,(写了五遍简直要写吐),差不多就是如下格式:
void dfs(int x){ 求x所在子树的重心 root (记得 用临时变量来存每次求出的root,因为root身为一个全局变量,之后的求重心过程中会改变root的值) int rt=root; vis[rt]=1; 根据题意处理这个子树中过rt的路径 结束}
第一遍的时候,细节各种恶心,有的地方要调好长时间才能发现细节性的错误,有的题还要卡vector,蒟蒻决定以后时间不是特别紧的情况下舍弃vector,用手写边表orz。
至于树的重心,感觉这篇文章写的可以,帮大忙了:
http://blog.csdn.net/xdu_truth/article/details/9104629
多个子树求重心:
void dfssize(int x,int fa){ size[x]=1; for (int i=head[x];i!=0;i=edge[i].next) { int v=edge[i].v; if (vis[v]!=1&&v!=fa) { dfssize(v,x); size[x]+=size[v]; } }}void dfsroot(int x,int fa,int num){ int tmp=-1; for (int i=head[x];i!=0;i=edge[i].next) { int v=edge[i].v; if (vis[v]!=1&&v!=fa) { dfsroot(v,x,num); tmp=max(tmp,size[v]); } } tmp=max(tmp,num-size[x]); if (tmp<bijiao) { bijiao=tmp; root=x; }}void dfs(int x){ bijiao=n+1; dfssize(x,x); dfsroot(x,x,size[x]); int rt=root;vis[rt]=1;........................}
差不多就是这样了,写的丑就丑吧。第一道题:poj1741.这道题也计算出根节点到所有当前子树节点的距离,存在一个数组之中,然后sort。。。用奇技淫巧的方法可已将排序之后的距离们O(n)的处理出有多少小于k的路径:
但是这会把不过根节点的路径重复计算,因此还要减去子树中的路径,具体看代码:
int calc(int x,int fa,int d){ int ret=0; tot=0;dfsdis(x,fa,d); //cout<<rt<<' '<<tot<<endl; //for (int i=1;i<=tot;i++) //cout<<dis[i]<<' '; //cout<<endl; //cout<<ans<<endl; sort(dis+1,dis+1+tot); int l=1,r=tot; while(l<r) { while (dis[l]+dis[r]>k && l<r) r--; ret+=r-l; l++; } return ret;}void dfs(int x){ bijiao=9999999; dfssize(x,x); dfsroot(x,x,size[x]); int rt=root; vis[rt]=1; ans+=calc(rt,rt,0); for (int i=0;i<lin[rt].size();i++) { int v=lin[rt][i].v; if (vis[v]==0) { ans-=calc(v,rt,lin[rt][i].d); dfs(v); } } }
(鉴于有五道题,我就不一一附完整代码了。。。。)
接下来一道题:
hdu4812
这道题和上道题略有不同,即问有多少条路径,符合路径上所有节点的权值乘积模1000003等于k,呵呵呵,
刚一看题,woca,这难道不是上一道题的简化版么,等于k好简单,然后分分钟打脸,不得已看了别人的题解,哎,满满都是泪,这道题方法不能像上一道题一样,要用一个新方法来计算。
建议先不做这道题,简直恶心的可以,不禁要注意long long这种变量类型,还要预处理出逆元,还要卡一次蒟蒻们的vector,还要开c++的栈优化,跳了好长时间,这道题必须要附代码,以此明此题恶心:
#include<iostream>#include<algorithm>#include<stdio.h>#include<vector>#include<string.h>#define maxn (2*100005)#define mmod (1000003)#define mm (2*1000010)#pragma comment(linker,"/STACK:102400000,102400000")using namespace std;#pragma comment(linker,"/STACK:102400000,102400000")typedef long long ll;struct node{ int v,next;}edge[maxn*2];int head[maxn*2],tot2;void addedge(int ui,int vi){ edge[tot2].v=vi; edge[tot2].next=head[ui]; head[ui]=tot2++; edge[tot2].v=ui; edge[tot2].next=head[vi]; head[vi]=tot2++;}int root,tot,xx,n,has[mm],id[maxn],flag[mm],ansl,ansr;int bijiao,size[maxn],vis[maxn];ll dis[maxn],a[maxn],ni[mm],k;inline ll read(){ ll x=0;char ch=getchar(); while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x;}void ext_gcd(ll a,ll b,ll &x,ll &y){ if (b==0) { x=1;y=0; return ; } else { ext_gcd(b,a%b,x,y); int t=x;x=y; y=t-a/b*y; return ; }}void dfssize(int x,int fa){ size[x]=1; for (int i=head[x];i!=0;i=edge[i].next) { int v=edge[i].v; if (vis[v]!=1&&v!=fa) { dfssize(v,x); size[x]+=size[v]; } }}void dfsroot(int x,int fa,int num){ int tmp=-1; for (int i=head[x];i!=0;i=edge[i].next) { int v=edge[i].v; if (vis[v]!=1&&v!=fa) { dfsroot(v,x,num); tmp=max(tmp,size[v]); } } tmp=max(tmp,num-size[x]); if (tmp<bijiao) { bijiao=tmp; root=x; }}void dfsdis(int x,int fa,ll p){ tot++; dis[tot]=p*a[x]%mmod; id[tot]=x; ll tmp=dis[tot]; for (int i=head[x];i!=0;i=edge[i].next) { int v=edge[i].v; if (vis[v]!=1&&v!=fa) dfsdis(v,x,tmp); }}void getans(int l,int r){ if (l>r) swap(l,r); if (l<ansl) ansl=l,ansr=r; else if (l==ansl) ansr=min(ansr,r); return ;}void dfs(int x){ bijiao=99999999; dfssize(x,x); dfsroot(x,x,size[x]); int rt=root; vis[rt]=1; xx++; //cout<<rt<<endl; for (int j=head[rt];j!=0;j=edge[j].next) { int v=edge[j].v; if (vis[v]==1) continue; tot=0; dfsdis(v,rt,1); for (int i=1;i<=tot;i++) { if ((dis[i]*a[rt])%mmod==k) getans(id[i],rt); ll tmp=((ni[(dis[i]*a[rt])%mmod])*k)%mmod; //cout<<dis[i]*a[rt]<<' '<<tmp<<endl; //cout<<flag[tmp]<<endl; //cout<<xx<<endl; if (flag[tmp]!=xx) continue; //cout<<has[tmp]<<' '<<id[i]<<endl; getans(has[tmp],id[i]); } for (int i=1;i<=tot;i++) { if ((flag[dis[i]]!=xx)||(has[dis[i]]>id[i])) has[dis[i]]=id[i],flag[dis[i]]=xx; //cout<<dis[i]<<' '<<id[i]<<endl; } } for (int i=head[rt];i!=0;i=edge[i].next) { int v=edge[i].v; if (vis[v]!=1) dfs(v); }}int main(){ for (int i = 0;i < mmod;i++) { ll y; ext_gcd(i*1ll, mmod*1ll, ni[i], y); ni[i] %= mmod, ni[i] = (ni[i]+mmod)%mmod; } while(scanf("%d%I64d",&n,&k)!=EOF) { xx=0;tot2=1; memset(flag,0,sizeof(flag)); memset(has,0,sizeof(has)); memset(head,0,sizeof(head)); for (int i=1;i<=n;i++) { a[i]=read(); vis[i]=0; } for (int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); addedge(x,y); } //cout<<(ni[20]*60)%mmod<<endl; ansl=9999999,ansr=9999999; dfs(1); if (ansl==9999999&&ansr==9999999) printf("No solution\n"); else printf("%d %d\n",ansl,ansr); }}
接下来两道题是codeforces161D,bzoj2152,这两道题与hdu4812是同一个类型,在做过那种恶心题后感觉这两道题都很简单,很容易就写出来并且A掉了,不过细节好还是要注意的。
最后是bzoj3697,这道题的思路很巧妙,和前几道题的做法不同,表示自己智商不够,只好看了hzwer聚聚的博客,自认为没有人家写得好就不附代码了。。呵呵呵。。
总之点分治的题就写这么几道了,
顺便说一句这博客编辑器真是恶心,不知道出了bug,写这点东西让我调格式与版式写了一小时,唉。。。
- 【蒟蒻的点分治专题训练】----5道题题解
- 点分治专题——bzoj 1468 &bzoj 2152 题解
- 【BZOJ】【P3697】【采药人的路径】【题解】【点分治】
- BZOJ 1316: 树上的询问 点分治题解
- 树的分治-点分治
- 【BZOJ】【P1468】【Tree】【题解】【点分治】
- 【BZOJ】【P2599】【IOI2011】【Race】【题解】【点分治】
- Poj1741[Tree]题解--点分治||Treap
- BZOJ2152 聪聪可可 点分治题解
- BZOJ 2599: [IOI2011]Race 点分治题解
- BZOJ 1468: Tree 点分治题解
- 【图论】点分治总结&POJ2114Boatherds题解
- 关于分治的入门专题
- NOJ寒假专题训练 Round #1 Search D~H题题解 另附A~C题解地址
- 树的点分治
- 树的点分治
- 点分治模板题
- 分治专题
- 在Linux下使用C++开发Nginx模块的编译配置
- HDU 2544 最短路
- 饿了么开源项目:Java Comparator生成器
- JAVA006-冒泡排序和方法
- 使用AndroidSdudio并新建多个module
- 【蒟蒻的点分治专题训练】----5道题题解
- 方法的重写(override)两同两小一大原则
- Use git within eclipse
- Workflow Demo
- Python lambda(匿名函数)函数总结
- 软件工程(九)
- c#串口温度数据的波形采集
- JavaWeb部分面试题
- Runtime 运行时:类与对象