poj4003 树形dp, rmq_st

来源:互联网 发布:steam淘宝礼物退款 编辑:程序博客网 时间:2024/05/03 05:50

很综合的题目,出得非常好

第一个问题是求以树中的每个节点为起点所能走的最长路:

首先,求出各个点的最长路,次长路,以及最长路的后继节点,再据此得到答案

第二个问题,需要rmq,并且维护一个队列,只要满足条件,队尾添加新元素,不然同时弹出队头

注意!dfs函数中tmp2为根走另一分支所得次长路,与最长路无公共路径!


#include <iostream>using namespace std;struct gtype {       int y,d,next;}g[100010];int first[50010],tot,x,y,d,s[50010],a[50010][4],n,m,q;int MIN[50001][20],MAX[50001][20];void add(int x,int y,int d) {     tot++;     g[tot].y = y;     g[tot].d = d;     g[tot].next = first[x];     first[x] = tot;}int dfs(int x,int fa) {    int tmp1 = 0, tmp2 = 0, vx = 0;    for (int t=first[x];t!=-1;t=g[t].next) {        int y = g[t].y;        if (y==fa) continue;        int tmp = g[t].d + dfs(y, x);        if (tmp > tmp1) {                tmp2 = tmp1;                tmp1 = tmp;                vx = y;        }        else if (tmp > tmp2) tmp2 = tmp;    }    a[x][0] = vx;    a[x][1] = tmp1;    a[x][2] = tmp2;    return tmp1;}     void find(int x,int fa,int ans) {     int vx = a[x][0];     int tmp1 = a[x][1];     int tmp2 = a[x][2];     if (ans > tmp1) {             tmp2 = tmp1;             tmp1 = ans;             vx = 0;     }     else if (ans > tmp2) tmp2 = ans;     s[x-1] = tmp1;     for (int t=first[x];t!=-1;t=g[t].next) {         int y = g[t].y;         if (y==fa) continue;         if (y==vx) find(y,x,tmp2+g[t].d);         else       find(y,x,tmp1+g[t].d);     }}int max(int x,int y) {    return s[x]>s[y]?x:y;}int min(int x,int y) {    return s[x]>s[y]?y:x;}void ST() {    int i,j;    for (i=0;i<=n;i++)                MIN[i][0]=MAX[i][0]=i;    for (j=1;1<<j<=n;j++)        for (i=0;i+(1<<j)-1<n;i++) {                                 MIN[i][j]=min(MIN[i][j-1],MIN[i+(1<<(j-1))][j-1]);                     MAX[i][j]=max(MAX[i][j-1],MAX[i+(1<<(j-1))][j-1]);        }    }int RMQ(int i,int j,int x) {//询问区间[i,j],x==1返回最大值下标,否则返回最小值下标     if (i>j) {             i^=j;j^=i;i^=j;    }    int k=0;    while (i+(1<<k)<j-(1<<k)+1) k++;    if(x==1)        return max(MAX[i][k],MAX[j-(1<<k)+1][k]);    return min(MIN[i][k],MIN[j-(1<<k)+1][k]);}int maxi(int a,int b) {    if (a>b) return a; else return b;}int main() {    while (scanf("%d%d",&n,&m)) {          if (n==0 && m==0) break;          tot = 0;          memset(g,0,sizeof(g));          memset(first,-1,sizeof(first));          for (int i=1;i<n;i++) {              scanf("%d%d%d",&x,&y,&d);              add(x,y,d);              add(y,x,d);          }          dfs(1,0);          find(1,0,0);          ST();          for (int i=1;i<=m;i++) {              scanf("%d",&q);              int head = 1, tail = 1, ans = 0;              while (tail <= n) {                    int tmp1 = s[RMQ(head-1,tail-1,0)];                    int tmp2 = s[RMQ(head-1,tail-1,1)];                    if (tmp2-tmp1<=q) {                          tail++;                          ans = maxi(ans,tail-head);                    }                    else { head++;tail++; }              }              printf("%d\n",ans);          }    }    return 0;}


原创粉丝点击