附题:
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 (tmpint 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<
(鉴于有五道题,我就不一一附完整代码了。。。。)
接下来一道题:
hdu4812
这道题和上道题略有不同,即问有多少条路径,符合路径上所有节点的权值乘积模1000003等于k,呵呵呵,
刚一看题,woca,这难道不是上一道题的简化版么,等于k好简单,然后分分钟打脸,不得已看了别人的题解,哎,满满都是泪,这道题方法不能像上一道题一样,要用一个新方法来计算。
建议先不做这道题,简直恶心的可以,不禁要注意long long这种变量类型,还要预处理出逆元,还要卡一次蒟蒻们的vector,还要开c++的栈优化,跳了好长时间,这道题必须要附代码,以此明此题恶心:
#include
#include
#include
#include
#include
#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 (tmpx;
}
}
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 (lelse 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<
接下来两道题是codeforces161D,bzoj2152,这两道题与hdu4812是同一个类型,在做过那种恶心题后感觉这两道题都很简单,很容易就写出来并且A掉了,不过细节好还是要注意的。
最后是bzoj3697,这道题的思路很巧妙,和前几道题的做法不同,表示自己智商不够,只好看了hzwer聚聚的博客,自认为没有人家写得好就不附代码了。。呵呵呵。。
总之点分治的题就写这么几道了,
顺便说一句这博客编辑器真是恶心,不知道出了bug,写这点东西让我调格式与版式写了一小时,唉。。。