zoukankan      html  css  js  c++  java
  • HDU 5957 Query on a graph (拓扑 + bfs序 + 树剖 + 线段树)

    题意:一个图有n个点,n条边,定义D(u,v)为u到v的距离,S(u,k)为所有D(u,v)<=k的节点v的集合 有m次询问(0<=k<=2):

    1 u k d:将集合S(u,k)的所有节点的权值加d

    2 u k:询问集合S(u,k)的所有节点的权值之和

    析:把这个图树成两部分,一个是一个环,然后剩下的森林。

    这个环可以用拓扑来求,看这个博客吧,讲的非常细了。

    http://blog.csdn.net/qq_31759205/article/details/75049074

    代码如下:

    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <cstdio>
    #include <string>
    #include <cstdlib>
    #include <cmath>
    #include <iostream>
    #include <cstring>
    #include <set>
    #include <queue>
    #include <algorithm>
    #include <vector>
    #include <map>
    #include <cctype>
    #include <cmath>
    #include <stack>
    #include <sstream>
    #include <list>
    #include <assert.h>
    #include <bitset>
    #include <numeric>
    #define debug() puts("++++");
    #define gcd(a, b) __gcd(a, b)
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define fi first
    #define se second
    #define pb push_back
    #define sqr(x) ((x)*(x))
    #define ms(a,b) memset(a, b, sizeof a)
    //#define sz size()
    #define pu push_up
    #define pd push_down
    #define cl clear()
    #define all 1,n,1
    #define FOR(i,x,n)  for(int i = (x); i < (n); ++i)
    #define freopenr freopen("in.txt", "r", stdin)
    #define freopenw freopen("out.txt", "w", stdout)
    using namespace std;
    
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair<LL, int> P;
    const int INF = 0x3f3f3f3f;
    const LL LNF = 1e17;
    const double inf = 1e20;
    const double PI = acos(-1.0);
    const double eps = 1e-8;
    const int maxn = 1e5 + 10;
    const int maxm = 1e6 + 5;
    const int mod = 10007;
    const int dr[] = {-1, 0, 1, 0};
    const int dc[] = {0, -1, 0, 1};
    const char *de[] = {"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
    int n, m;
    const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    inline bool is_in(int r, int c) {
      return r >= 0 && r < n && c >= 0 && c < m;
    }
    
    struct Edge{
      int to, next;
    };
    Edge edge[maxn<<1];
    int head[maxn], cnt;
    int in[maxn];
    
    void addEdge(int u, int v){
      edge[cnt].to = v;
      edge[cnt].next = head[u];
      head[u] = cnt++;
      ++in[v];
    }
    
    void topsort(){
      queue<int> q;
      for(int i = 1; i <= n; ++i)  if(in[i] == 1)  q.push(i);
      while(!q.empty()){
        int u = q.front();  q.pop();
        for(int i = head[u]; ~i; i = edge[i].next){
          int v = edge[i].to;
          if(in[v] > 1){
            --in[v];
            if(in[v] == 1)  q.push(v);
          }
        }
      }
    }
    
    int ch[maxn][2], p[maxn], fp[maxn], pos;
    int fa[maxn];
    int sonL[maxn], sonR[maxn], ssonL[maxn], ssonR[maxn];
    
    void bfs(int s){
      queue<int> q;
      q.push(s);
    
      while(!q.empty()){
        int u = q.front();  q.pop();
        sonL[u] = ssonL[u] = INF;
        sonR[u] = ssonR[u] = 0;
        for(int i = head[u]; ~i; i = edge[i].next){
          int v = edge[i].to;
          if(in[v] > 1 || fa[u] == v)  continue;
          p[v] = ++pos;
          fp[pos] = v;
          fa[v] = u;
          sonL[u] = min(sonL[u], p[v]);
          sonR[u] = max(sonR[u], p[v]);
          q.push(v);
        }
        ssonL[fa[u]] = min(ssonL[fa[u]], sonL[u]);
        ssonR[fa[u]] = max(ssonR[fa[u]], sonR[u]);
      }
    }
    
    LL sum[maxn<<2], addv[maxn<<2];
    inline void push_up(int rt){ sum[rt] = sum[rt<<1] + sum[rt<<1|1]; }
    inline void push_down(int rt, int len){
      int l = rt<<1, r = rt<<1|1;
      sum[l] += (len -  (len>>1)) * addv[rt];
      sum[r] += (len>>1) * addv[rt];
      addv[l] += addv[rt];
      addv[r] += addv[rt];
      addv[rt] = 0;
    }
    
    void update(int L, int R, int val, int l, int r, int rt){
      if(L > R)   return ;
      if(L <= l && r <= R){
        sum[rt] += (LL)(r - l + 1) * val;
        addv[rt] += val;
        return ;
      }
      if(addv[rt])  pd(rt, r - l + 1);
      int m = l + r >> 1;
      if(L <= m)  update(L, R, val, lson);
      if(R > m)   update(L, R, val, rson);
      pu(rt);
    }
    
    
    LL query(int L, int R, int l, int r, int rt){
      if(L > R)  return 0LL;
      if(L <= l && r <= R)  return sum[rt];
      if(addv[rt])  pd(rt, r - l + 1);
      int m = l + r >> 1;
      LL ans = 0;
      if(L <= m)  ans = query(L, R, lson);
      if(R > m)  ans += query(L, R, rson);
      return ans;
    }
    
    void praper(){
      topsort();
      for(int u = 1; u <= n; ++u)  if(in[u] > 1){
        int j = 0;
        for(int i = head[u]; ~i; i = edge[i].next){
          int v = edge[i].to;
          if(in[v] > 1)  ch[u][j++] = v;
        }
        p[u] = ++pos;
        fp[pos] = u;
        fa[u] = 0;
        bfs(u);
      }
    }
    
    void init(){
      ms(head, -1);  cnt = 0;  ms(in, 0);
      pos = 0;  ms(sum, 0);  ms(addv, 0);
    }
    
    void update(int u, int k, int val){
      int f = fa[u];
      if(k == 0)  update(p[u], p[u], val, all);  // self
      else if(k == 1){
        if(in[u] > 1){  // on the circle
          update(p[ch[u][0]], p[ch[u][0]], val, all);  // left neighbor
          update(p[ch[u][1]], p[ch[u][1]], val, all);  // right neighbor
        }
        else  // not on the circle
          update(p[f], p[f], val, all);  // its father
        update(sonL[u], sonR[u], val, all); // left son - right son
        update(p[u], p[u], val, all);  //self
      }
      else {
        if(in[u] > 1){  // on the circle
          int vv[2], cnt = 0;
          for(int i = 0; i < 2; ++i){
            int v = ch[u][i];
            update(p[v], p[v], val, all);  // its neighbor
            update(sonL[v], sonR[v], val, all);  // its neighbor's sons
            for(int j = 0; j < 2; ++j){
              int t = ch[v][j];
              if(t == u || t == ch[u][i^1])  continue;  // insure not calculate twice times
              if(cnt == 1 && vv[0] == t)  continue;
              vv[cnt++] = t;
            }
          }
          for(int i = 0; i < cnt; ++i)
            update(p[vv[i]], p[vv[i]], val, all);  // its neighbor's neighbor
          update(p[u], p[u], val, all);  // self take care  the below have no
        }
        else{  // not on the circle
          update(p[f], p[f], val, all);  // its father
          update(sonL[f], sonR[f], val, all);  // its father's son
          if(in[f] > 1){  // its father is on the circle
            update(p[ch[f][0]], p[ch[f][0]], val, all);  // its father's left neighbor
            update(p[ch[f][1]], p[ch[f][1]], val, all);  // its father's fight neighbor
          }
          else  // its father is not on the circle
            update(p[fa[f]], p[fa[f]], val, all);  // its father's father
        }
        update(sonL[u], sonR[u], val, all);  // sons
        update(ssonL[u], ssonR[u], val, all);  // ssons
      }
    }
    
    LL query(int u, int k){  // the same as update
      int f = fa[u];
      LL ans = 0;
      if(k == 0)  return query(p[u], p[u], all);
      else if(k == 1){
        ans = query(sonL[u], sonR[u], all) + query(p[u], p[u], all);
        if(in[u] == 1)  ans += query(p[f], p[f], all);
        else ans += query(p[ch[u][0]], p[ch[u][0]], all) + query(p[ch[u][1]], p[ch[u][1]], all);
      }
      else{
        ans = query(sonL[u], sonR[u], all) + query(ssonL[u], ssonR[u], all);
        if(in[u] > 1){
          ans += query(p[u], p[u], all);
          int vv[2], cnt = 0;
          for(int i = 0; i < 2; ++i){
            int v = ch[u][i];
            ans += query(p[v], p[v], all);
            ans += query(sonL[v], sonR[v], all);
            for(int j = 0; j < 2; ++j){
              int t = ch[v][j];
              if(t == u || t == ch[u][i^1])  continue;
              if(cnt == 1 && t == vv[0])  continue;
              vv[cnt++] = t;
            }
          }
          for(int i = 0; i < cnt; ++i)
            ans += query(p[vv[i]], p[vv[i]], all);
        }
        else {
          ans += query(p[f], p[f], all) + query(sonL[f], sonR[f], all);
          if(in[f] > 1)  ans += query(p[ch[f][0]], p[ch[f][0]], all) + query(p[ch[f][1]], p[ch[f][1]], all);
          else ans += query(p[fa[f]], p[fa[f]], all);
        }
      }
      return ans;
    }
    
    int main(){
      int T;  cin >> T;
      while(T--){
        scanf("%d", &n);
        init();
        for(int i = 0; i < n; ++i){
          int u, v;
          scanf("%d %d", &u, &v);
          addEdge(u, v);
          addEdge(v, u);
        }
        praper();
        scanf("%d", &m);
        char op[10];
        int u, k, d;
        while(m--){
          scanf("%s %d %d", op, &u, &k);
          if(op[0] == 'M'){
            scanf("%d", &d);
            update(u, k, d);
          }
          else printf("%I64d
    ", query(u, k));
        }
      }
      return 0;
    }
    

      

  • 相关阅读:
    开始学习编写用于 Windows SideShow 设备的小工具【转】
    Windows Mobile 6.5 Developer Tool Kit 下载
    Microsoft Security Essentials 微软免费杀毒软件下载
    SQL Server 2008 空间数据存储摘抄(SRID 点 MultiPoint LineString MultiLineString 多边形 MultiPolygon GeometryCollection)
    Vista Sidebar Gadget (侧边栏小工具)开发教程 (2)
    Vista Sidebar Gadget (侧边栏小工具)开发教程 (4)
    负载测试、压力测试和性能测试的异同
    Windows Server 2008 Vista Sidebar Gadget (侧边栏小工具) 入门开发实例
    Silverlight Tools 安装失败 解决办法
    SQL Server 2008 空间数据库 空间索引概念及创建(取自帮助)
  • 原文地址:https://www.cnblogs.com/dwtfukgv/p/7688480.html
Copyright © 2011-2022 走看看