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
- HDU4812 树分治 模板
- hdu4812(树分治)
- 【HDU4812】multik {树分治+乘法逆元}
- [树的点分治] [HDU4812] D Tree
- hdu4812 D Tree(点分治)
- HDU4812
- hdu4812 D Tree 【点分治+逆元+hash】
- HDU4812 D tree 【点分治 + 乘法逆元】
- hdu4812 D Tree,平衡树,启发式合并
- 树分治(点分治模板)poj-1741 Tree
- 树分治(点分治模板)poj-1741 Tree
- 树分治(点分治模板)poj-1741 Tree
- 【POJ1741】Tree 树分治 模板咯?
- 动态树分治——模板整理
- POJ 1741 Tree (树分治模板题)
- poj 1741 洛谷 3806 【模板】点分治1 树的分治 点分治
- poj 1741 洛谷 3806 【模板】点分治1 树的分治 点分治
- cdq分治模板
- 华为机试 ——消消乐
- linux添加个定时备份脚本
- 康威生命游戏的学习
- 黑马程序员-Java高级:多线程
- Codeforces Round #307 (Div. 2) A. GukiZ and Contest
- HDU4812 树分治 模板
- linux下使用g++编译包含多个库的c++的方法
- 开源项目Logger源码分析-----一个好看、简单、强大的logcat信息输出项目
- OC - 知识点总结
- 今日总结
- POJ 2524 Ubiquitous Religions
- 面向对象,集合篇(2)
- Jquery-截取过长字符串
- 安倍首相の戦後70年談話全文