luogu P3806 点分治1

点分治算法很容易常数写大?不开O2就被卡常。

很裸的点分治,从选出的根开始往其余的子树搜,看一下当前经过的路径长度tot,k-tot是否在set中,在就找到了长度为k的路径。唯一要注意下的就是,当前子树经过的路径长度不能直接丢到set里,要搞一个临时的tpset来暂存下,搜完这棵子树再把这个tpset的里的路径长度丢进set。避免误算一个子树里折返跑的情况。

  1 #include <cstdio>
  2 #include <set>
  3 #include <cstring>
  4 using namespace std;
  5 set <int> st,tp;
  6 const int MAXN = 10100,inf = 1000000000;
  7 int head[MAXN],siz[MAXN],to[MAXN * 2],nxt[MAXN * 2],val[MAXN * 2];
  8 int cnt,n,m,k,sum,root,maxn;
  9 bool vis[MAXN];
 10 bool suc;
 11 void add(int x,int y,int v)
 12 {
 13     nxt[++cnt] = head[x];
 14     to[cnt] = y;
 15     head[x] = cnt;
 16     val[cnt] = v;
 17 } 
 18 void get_root(int x,int frm)
 19 {
 20     int mx = 0;
 21     siz[x] = 1;
 22     for (int i = head[x];i;i = nxt[i])
 23     {
 24         if (vis[to[i]] == true || to[i] == frm) 
 25             continue; 
 26         get_root(to[i],x);
 27         mx = max(mx,siz[to[i]]);
 28         siz[x] += siz[to[i]];
 29     }
 30     mx = max(mx,sum - siz[x]);
 31     if (mx < maxn)
 32     {
 33         maxn = mx;
 34         root = x;
 35     }
 36 }
 37 void dfs(int x,int frm,int tot)
 38 {
 39     if (st.count(k - tot) == 1)
 40     {
 41         suc = true;
 42         return;
 43     }
 44     tp.insert(tot);
 45     for (int i = head[x];i;i = nxt[i])
 46     {
 47         if (vis[to[i]] == true || to[i] == frm)
 48             continue;
 49         dfs(to[i],x,tot + val[i]);
 50         if (suc) return;
 51     }
 52 }
 53 void pot_div(int x)
 54 {
 55     st.clear();
 56     st.insert(0);
 57     vis[x] = true;
 58     for (int i = head[x];i;i = nxt[i])
 59     {
 60         if (vis[to[i]] == true)
 61             continue;
 62         dfs(to[i],x,val[i]);
 63         if (suc) return;
 64         set <int> ::iterator it;
 65         for (it = tp.begin();it != tp.end();it++)
 66             st.insert(*it);
 67         tp.clear();
 68     }
 69     for (int i = head[x];i;i = nxt[i])
 70     {
 71         if (vis[to[i]] == true)
 72             continue;
 73         sum = n;
 74         maxn = inf;
 75         get_root(to[i],x);
 76         pot_div(root);
 77         if (suc) return;
 78     }
 79 }
 80 int main()
 81 {
 82     scanf("%d%d",&n,&m);
 83     int tx,ty,tw;
 84     for (int i = 1;i <= n - 1;i++)    
 85     {
 86         scanf("%d%d%d",&tx,&ty,&tw);
 87         add(tx,ty,tw);
 88         add(ty,tx,tw);
 89     }
 90     for (int i = 1;i <= m;i++)
 91     {
 92         suc = false;
 93         sum = n;
 94         maxn = inf;
 95         memset(vis,0,sizeof(vis));
 96         get_root(1,0);
 97         scanf("%d",&k);
 98         pot_div(root);
 99         if (suc)
100             printf("AYE\n");
101         else
102             printf("NAY\n");
103     }
104     return 0;
105 }

猜你喜欢

转载自www.cnblogs.com/iat14/p/10533125.html
今日推荐