HDU4812 树分治 模板

来源:互联网 发布:电视频道网络直播 编辑:程序博客网 时间:2024/06/06 06:45

每次找一个树的重心x删除,用f[i]表示任意节点到重心中,乘积的mod为i的最小的点的编号(实际是一个编号加一个判重)

例外此题时限卡得比较紧张,所以for循环中不能多次调用a[x],size()函数

关于树的重心:所有子树的最大节点数最小的点,也就是所有点到他的距离之和最短

详情:http://blog.csdn.net/pi9nc/article/details/12394117#t7 和

参考:NOI论文《分治算法在树的路径问题中的应用》

题解参考:主席的博客 

注意加栈外挂,用c++提交

我的代码:

/* * Author: NICK WONG * Created Time:  2015/8/14 16:19:55 * File Name: 4812_my.cpp */#pragma comment(linker, "/STACK:102400000,102400000")#include<iostream>#include<sstream>#include<fstream>#include<vector>#include<list>#include<deque>#include<queue>#include<stack>#include<map>#include<set>#include<bitset>#include<algorithm>#include<cstdio>#include<cstdlib>#include<cstring>#include<cctype>#include<cmath>#include<ctime>#include<iomanip>using namespace std;#define out(x) cout<<#x<<": "<<x<<endlconst double eps(1e-8);const int maxn=101000;const long long maxint=-1u>>1;const long long maxlong=maxint*maxint;typedef long long lint;const int mod=1e6+3;vector<int> a[maxn];lint h,f[mod+10],p[mod+10];int n,m,son[maxn],mx[maxn],d[maxn];bool v[maxn];pair<int,int> ans,as=make_pair(maxint,maxint);inline void change(pair<int, int> b){    if (b.first>b.second) swap(b.first,b.second);    if (b<ans) ans=b;}int find(int x){    int k=mod-2,ans=1;    while(k)    {        if (k&1) ans=(lint)ans*x%mod;        x=(lint)x*x%mod;        k>>=1;    }    return ans;}void init(){    for (int i=1; i<=n; i++)    {        scanf("%d",&d[i]);        a[i].clear();    }    for (int i=1; i<=n-1; i++)    {        int x,y;        scanf("%d%d",&x,&y);        a[x].push_back(y);        a[y].push_back(x);    }}void fdfs(int x, int fa){    son[x]=1; mx[x]=0;    //for (int i=0; i<(int)a[i].size(); i++)    for (int i=a[x].size()-1; i>=0; i--)        if (!v[a[x][i]] && a[x][i]!=fa)        {            fdfs(a[x][i],x);            son[x]+=son[a[x][i]];            mx[x]=max(mx[x],son[a[x][i]]);        }}int froot(int x, int fa, int sum){    int ret=x,y;    mx[x]=max(mx[x],sum-son[x]);    //for (int i=0; i<(int)a[i].size(); i++)    for (int i=a[x].size()-1; i>=0; i--)        if (!v[a[x][i]] && a[x][i]!=fa)        {            y=froot(a[x][i],x,sum);            if (mx[y]<mx[ret]) ret=y;        }    return ret;}void dfs(int x, int fa, lint s, int type){    s=s*d[x]%mod;    if (type)//exclude    {        lint u=f[p[s]*m%mod]-h*maxn;        if (u>0)        {            change(make_pair((int)u,x));        }    } else    //if (type==0)    {        if (f[s]-h*maxn<=0 || f[s]>h*maxn+x) f[s]=h*maxn+x;     }    //for (int i=0; i<(int)a[x].size(); i++)    for (int i=a[x].size()-1; i>=0; i--)        if (!v[a[x][i]] && a[x][i]!=fa) dfs(a[x][i],x,s,type);}        void work(){    memset(v,false,sizeof(v));    ans=as;    //memset(f,0,sizeof(f));    for (int i=1; i<=n; i++)        while(!v[i])        {            fdfs(i,i);            int x=froot(i,i,son[i]);            v[x]=true;            //out(x);            h++;            f[d[x]]=h*maxn+x;            //for (int j=0; j<(int)a[x].size(); j++)            for (int j=a[x].size()-1; j>=0; j--)                if (!v[a[x][j]])                {                    dfs(a[x][j],x,1,1);                    dfs(a[x][j],x,d[x],0);                }        }    if (ans==as) cout<<"No solution"<<endl; else cout<<ans.first<<" "<<ans.second<<endl;}int main(){    for (int i=1; i<=mod; i++) p[i]=find(i);     while(cin>>n>>m)    {        init();        work();    }    return 0;}

把vawait的代码注释之后:

/* * Author:  vawait * Created Time:  2014年05月08日 星期四 16时30分25秒 * File Name: 1.cpp */#pragma comment(linker, "/STACK:102400000,102400000")#include<cstdio>#include<iostream>#include<cstring>#include<cstdlib>#include<cmath>#include<algorithm>#include<string>#include<map>#include<set>#include<vector>#include<queue>#include<stack>using namespace std;#define rep(i, a, b) for (int i = (a); i <= (b); ++i)#define red(i, a, b) for (int i = (a); i >= (b); --i)#define clr( x , y ) memset(x,y,sizeof(x))#define sqr(x) ((x) * (x))#define mp make_pair#define pb push_back#define x first#define y secondtypedef long long lint;#pragma comment(linker,"/STACK:102400000,102400000")const int mm = 1000003;const lint qq = 100000;//基于节点总数,后面用于判重int n , m , q = 0 , d[100100] , s[100100] , mx[100100];vector < int > a[100100];lint f[1001000] , p[1001000];bool v[100100];pair < int , int > ans , as = mp( 100000000 , 100000000 );void MX(pair < int , int > k) {//使用pair进行比较if ( k.x > k.y ) swap( k.x , k.y );//pair的first,second被重新定义了if ( k < ans ) ans = k;}int find(int t) //逆元快速幂{int k = mm - 2 , s = 1;while ( k ) {if ( k & 1 ) s = (lint) s * t % mm;t = (lint) t * t % mm;k >>= 1;}return s;}void init()//初始化{int x , y;rep(i,1,n) scanf("%d",&d[i]) , v[i] = 1 , a[i].clear();//v[i]==1表示节点没有被删除,0表示被删除了rep(i,2,n) {scanf("%d%d",&x,&y);a[x].pb( y );a[y].pb( x );}ans = as;}void fdfs(int t,int fa)//统计儿子总数{s[t] = 1; mx[t] = 0;red(i,a[t].size()-1,0) if ( a[t][i] != fa && v[a[t][i]] ) {fdfs( a[t][i] , t );s[t] += s[a[t][i]]; //s[t]保存t为根的子树的节点个数mx[t] = max( mx[t] , s[a[t][i]] );//最多的儿子总数是什么}}int froot(int t,int m, int fa) //找重心,m表示t所在整棵树的节点总数(注意不仅仅是子树,而且随着删点m是变化){int x = t , y;mx[t] = max( mx[t] , m - s[t] );//mx[t]表示把t删除后所有子树中的最大点数,m-s[t]表示t的父亲为根的节点数//red(i,a[t].size()-1,0) if ( v[a[t][i]] && s[t] > s[a[t][i]] ) { //why s[t] > s[a[t][i]]red(i,a[t].size()-1,0) if ( a[t][i]!=fa && v[a[t][i]]  ) { //why s[t] > s[a[t][i]]y = froot( a[t][i] , m ,t);if ( mx[y] < mx[x] ) x = y;}return x;//返回重心}void dfs(int t,int fa,lint s,int k)//进行匹配操作,当前点t.父亲fa,乘积s,操作类型k{s = s * d[t] % mm;//从重心(根据k可能不包括)到当前点t的乘积if ( k ) {//不包括重心x,k==1,进行查找操作lint x = f[p[s]*m%mm] - q * qq;//m为题目中的余数kif ( x > 0 ) MX( mp( (int)x , t ) );} else {//包括重心x,插入在哈希表里面lint x = q * qq + t;if ( f[s] < q * qq || f[s] > x ) f[s] = x;//<q*qq表示不是当前第q棵树的值,可以直接替换}red(i,a[t].size()-1,0)         if ( v[a[t][i]] && a[t][i] != fa ) dfs( a[t][i] , t , s , k );//继续递归}void work(){rep(i,1,n) while ( v[i] ) {//把跟i点的树都进行找重心、删点的操作,直到i这个点被删除fdfs( i , 0 );int x = froot( i , s[i] , i );v[x] = 0;//把重心x标记为不可用,也就删点q ++;//当前这个x点也要放到hash里面f[d[x]] = q * qq + x;//qq为点的总数,q表示是第几棵树,+qq*q为了判重red(j,a[x].size()-1,0) if ( v[a[x][j]] ) {//要用downto,否则多次调用a[x].size函数会超时dfs( a[x][j] , x , 1 , 1 );//不包括重心xdfs( a[x][j] , x , d[x] , 0 );//包括重心x}}if ( ans == as ) puts("No solution"); else printf("%d %d\n",ans.x,ans.y);}int main(){rep(i,1,mm) p[i] = find( i );//预处理100万的逆元while ( cin >> n >> m ) {init();work();}    return 0;}

还有修改的BFS版本(改成手写队列,一切都是为了时限):

struct node{    int x,fa;    lint s;    int type;    node(int x=0, int fa=0, lint s=0, int type=0):x(x),fa(fa),s(s),type(type) {}} q[maxn];void bfs(int x, int fa, lint s, int type){    //queue<node> q;    int st=1,en=1;    q[1].x=x; q[1].fa=fa; q[1].s=s; q[1].type=type;    //q.push(node(x,fa,s,type));    while(st<=en)    {        //node tmp=q.front(); q.pop();        x=q[st].x; fa=q[st].fa; s=q[st].s; type=q[st].type;           s=s*d[x]%mod;        if (type)//exclude        {            lint u=f[p[s]*m%mod]-h*maxn;            if (u>0)            {                change(make_pair((int)u,x));            }        } else            if (type==0)            {                if (f[s]-h*maxn<=0 || f[s]>h*maxn+x) f[s]=h*maxn+x;             }        //for (int i=0; i<(int)a[x].size(); i++)        for (int i=a[x].size()-1; i>=0; i--)            if (!v[a[x][i]] && a[x][i]!=fa) //q.push(node(a[x][i],x,s,type));        {            en++;            q[en].x=a[x][i]; q[en].fa=x; q[en].s=s; q[en].type=type;        }        st++;    }}





0 0
原创粉丝点击