发一下牢骚和主题无关:
擒贼先擒王,每次赛后总结CF的题,我都爱好先搞E题,而且E题一般是我最爱的数据结构题,搞起来特爽
E题:给你一棵树,求满意距离之和<=L 且 路径上的权值之和<= w的点对量数。。。
类似的目题:http://poj.org/problem?id=1741
方法是点的分治,详细参考漆子超的论文,分治算法在树的路径中的应用,论文里头经已讲了很详细了
会了poj 1741的话,其实这道题就是多了一个制限,还是排序,扫描,不过在求的时候须要用树状组数维护一下,其实很简单,不过我还是调试了良久,,,,,代码力能与思维力能都须要精雕细琢啊。
在求一个二元组序列有多少对满意件条时卡了良久,看大神们都是加了一个0 0进去,我就是不想加,于是越写越烦,不是少算就是多算,最后冷静下来新重想了想,那还是先算成两倍的吧
我的那个calc函数略挫,,,,
poj 1741
#include<cstdio> #include<cstring> #include<vector> #include<algorithm> using namespace std; const int MAX_N = 100010; struct Edge{ int b , w; Edge() {} Edge(int b,int w): b(b),w(w){ } }; #define Tr(it,x) for(vector<Edge>::iterator it = x.begin(); it!=x.end();it++) vector<Edge> edge[MAX_N]; int N , K; int size[MAX_N] ; int opt[MAX_N]; bool del[MAX_N] ; long long Ans ; vector<int> tnode; void Dfs(int u,int fa) { tnode.push_back(u); opt[u] = 0; size[u] = 1; Tr(it,edge[u]) { int v = it->b; if(!del[v] && v!=fa){ Dfs(v , u); opt[u] = max(opt[u],size[v]); size[u] += size[v]; } } } int Find(int u) // find the centre of gravity { Dfs(u,-1); int who = -1 , mx = MAX_N; for(vector<int>::iterator it = tnode.begin(); it != tnode.end(); it++) { opt[*it] = max(opt[*it],size[u]-size[*it]); if(mx > opt[*it]) { mx = opt[*it]; who = *it; } } return who; } vector<int> all , ch[MAX_N]; void Get_dis(int u,int fa,int len,vector<int> &ch) { ch.push_back(len); all.push_back(len); Tr(it,edge[u]) { if(it->b!=fa && !del[it->b]) { Get_dis(it->b,u,len+it->w,ch); } } } long long calc(vector<int> dist) { long long ans = 0; int pt = 0 , sz = dist.size(); sort(dist.begin(),dist.end()); for(int i = 0,j = sz - 1;i <= j;i++) { while(i <= j && dist[i] + dist[j] > K) { j--; } if(i < j) ans += j - i; } return ans; } void Solve(int u) { tnode.clear(); u = Find(u); // the gravity center all.clear(); // all of the distances int nch = 0; // count of sons all.push_back(0); Tr(it,edge[u]) { ch[nch].clear(); if(!del[it->b]) Get_dis(it->b,u,it->w,ch[nch++]); } Ans += calc(all); for(int i = 0; i < nch; i++) Ans -= calc(ch[i]); del[u] = true; Tr(it,edge[u]) if(!del[it->b]) Solve(it->b); } int main() { int a,b,w; while(scanf("%d%d",&N,&K),N||K) { for(int i = 1; i <= N; i++) edge[i].clear(),del[i]=false; for(int i = 1; i < N; i++) { scanf("%d%d%d",&a,&b,&w); edge[a].push_back(Edge(b,w)); edge[b].push_back(Edge(a,w)); } Ans = 0; Solve(1); printf("%I64d\n",Ans); } return 0; }
CROC round2 E
// http://poj.org/problem?id=1741 #include<cstdio> #include<cstring> #include<vector> #include<algorithm> using namespace std; const int MAX_N = 100010; struct Edge{ int b , w; Edge() {} Edge(int b,int w): b(b),w(w){ } }; #define Tr(it,x) for(vector<Edge>::iterator it = x.begin(); it!=x.end();it++) vector<Edge> edge[MAX_N]; int N , K; int size[MAX_N] ; int opt[MAX_N]; bool del[MAX_N] ; long long Ans ; vector<int> tnode; void Dfs(int u,int fa) { tnode.push_back(u); opt[u] = 0; size[u] = 1; Tr(it,edge[u]) { int v = it->b; if(!del[v] && v!=fa){ Dfs(v , u); opt[u] = max(opt[u],size[v]); size[u] += size[v]; } } } int Find(int u) // find the centre of gravity { Dfs(u,-1); int who = -1 , mx = MAX_N; for(vector<int>::iterator it = tnode.begin(); it != tnode.end(); it++) { opt[*it] = max(opt[*it],size[u]-size[*it]); if(mx > opt[*it]) { mx = opt[*it]; who = *it; } } return who; } vector<pair<int,int> > all , ch[MAX_N]; void Get_dis(int u,int fa,int len,vector<pair<int,int> > &ch,int sum) { ch.push_back(make_pair(sum,len)); all.push_back(make_pair(sum,len)); Tr(it,edge[u]) { if(it->b!=fa && !del[it->b]) { Get_dis(it->b,u,len+it->w,ch,sum+1); } } } struct BIT{ int c[MAX_N]; int maxn ; void init(int n) { maxn = n; memset(c,0,sizeof(int)*n); } void insert(int x,int d) { for(x++;x<=maxn;x+=x&-x) c[x] += d; } int sum(int x) { int ans = 0; for(x++;x;x-=x&-x) ans += c[x]; return ans; } }bit; int L , W; int cmp(pair<int,int> a, pair<int,int> b) { if(a.second != b.second)return a.second < b.second; return a.first < b.first; } long long calc(vector<pair<int,int> > d,bool f) //这个函数写挫了,囧 { long long ans = 0; int pt = 0 , sz = d.size(); int mxd = 0; for(int i = 0; i < sz ; i++) { mxd = max(mxd,d[i].first); } bit.init(mxd+2); sort(d.begin(),d.end(),cmp); int cnt = 0; int j = 0; for(int i = sz - 1 ; i >= 0; i--) {// cnt : 单个点到根满意件条的个数,独单计统出来 if(f && d[i].first <= L && d[i].second <= W) cnt++; while(j < sz && d[j].second + d[i].second <= W) { bit.insert(d[j].first,1); j++; } if(L >= d[i].first){ ans += bit.sum(min(mxd,L-d[i].first)); if(j > i) if(d[i].first+d[i].first <= L) ans --; // 自己 与 自己不能算点对,要去掉 } } ans += cnt * 2; return ans; } void Solve(int u) { tnode.clear(); u = Find(u); // the gravity center all.clear(); // all of the distances int nch = 0; // count of sons Tr(it,edge[u]) { ch[nch].clear(); if(!del[it->b]) Get_dis(it->b,u,it->w,ch[nch++],1); } Ans += calc(all,true); for(int i = 0; i < nch; i++) Ans -= calc(ch[i],false); del[u] = true; Tr(it,edge[u]) if(!del[it->b]) Solve(it->b); } int main() { int a,b,w; while(scanf("%d%d%d",&N,&L,&W)!=EOF) { for(int i = 1; i <= N; i++) edge[i].clear(),del[i]=false; for(int i = 2; i <= N; i++) { scanf("%d%d",&a,&w); edge[i].push_back(Edge(a,w)); edge[a].push_back(Edge(i,w)); } Ans = 0; Solve(1); printf("%I64d\n",Ans/2); } return 0; }
文章结束给大家分享下程序员的一些笑话语录: 很多所谓的牛人也不过如此,离开了你,微软还是微软,Google还是Google,苹果还是苹果,暴雪还是暴雪,而这些牛人离开了公司,自己什么都不是。