zoukankan      html  css  js  c++  java
  • hdu4812 D Tree

    树上的点分治。

    首先为了避免超时预处理逆元,对于x(<mod),我们希望找到f-1(x) = y 满足y * x % mod = k。

    由存在a, b : x *a + y * b = gcd(x, y), mod 为素数,故有 x * a + mod * b = 1。

    由EXTENDED-EUCLID找出a (< mod)。

    对于树上的分治,首先找出当前树的重心,处理剔除重心后的各个子树,合法链属于其中一个子树或者经过树根。

    acm.hdu.edu.cn/showproblem.php?pid=4812

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #pragma comment(linker,"/STACK:102400000,102400000")
      5 
      6 using namespace std;
      7 typedef __int64 LL;
      8 const int inf = 0x3f3f3f3f;
      9 const int maxn = 1e5 + 10;
     10 const int mod = 1e6 + 3;
     11 
     12 struct Edge{
     13     int to, next;
     14 }edge[maxn * 2];
     15 int head[maxn], f[mod], belong[mod], g[mod];
     16 bool vis[maxn];
     17 int n, N, root;
     18 LL K, val[maxn], path[maxn];
     19 int cnt1, mini;
     20 LL d, x, y;
     21 int ans[2], sum[maxn], id[maxn];
     22 
     23 void addEdge(int u, int v){
     24     edge[N].next = head[u];
     25     edge[N].to = v;
     26     head[u] = N++;
     27 }
     28 
     29 void eEuclid(LL a, LL b){
     30     if(!b){
     31         d = a; x = 1; y = 0;
     32         return;
     33     }
     34     eEuclid(b, a % b);
     35     LL x1 = x;
     36     x = y;
     37     y = x1 - a / b * y;
     38 }
     39 
     40 void init(){
     41     //calculate inverse element
     42     for(int i = 0; i < mod; i++){
     43         eEuclid(mod, i);
     44         while(y < 0) y += mod;
     45         g[i] = y % mod;
     46     }
     47 }
     48 
     49 void getRoot(int u){
     50     sum[u] = 1;
     51     int maxii = 0;
     52     vis[u] = 1;
     53     for(int i = head[u]; i + 1; i = edge[i].next){
     54         int v = edge[i].to;
     55         if(vis[v]) continue;
     56         getRoot(v);
     57         sum[u] += sum[v];
     58         maxii = max(sum[v], maxii);
     59     }
     60     vis[u] = 0;
     61     maxii = max(maxii, sum[0] - sum[u]);
     62     if(maxii < mini) mini = maxii, root = u;
     63 }
     64 
     65 void update(int a, int b){
     66     if(a > b) swap(a, b);
     67     if(ans[0] == -1 || ans[0] > a){
     68         ans[0] = a, ans[1] = b;
     69         return;
     70     }
     71     if(ans[0] == a && ans[1] > b) ans[1] = b;
     72 }
     73 
     74 void dfs(int u, LL num){
     75     path[cnt1] = num * val[u] % mod;
     76     id[cnt1++] = u;
     77     LL tem = path[cnt1 - 1];
     78     vis[u] = 1;
     79     for(int i = head[u]; i + 1; i = edge[i].next){
     80         int v = edge[i].to;
     81         if(vis[v]) continue;
     82         dfs(v, tem);
     83     }
     84     vis[u] = 0;
     85 }
     86 
     87 void solve(int u, int cnt){
     88     if(cnt == 1) return;
     89     sum[0] = cnt;
     90     mini = inf;
     91     getRoot(u);
     92     vis[root] = 1;
     93     for(int i = head[root]; i + 1; i = edge[i].next){
     94         int v = edge[i].to;
     95         if(vis[v]) continue;
     96         cnt1 = 0;
     97         dfs(v, 1);
     98         for(int j = 0; j < cnt1; j++){
     99             if(path[j] * val[root] % mod == K) update(id[j], root);
    100             LL tem = K * g[path[j] * val[root] % mod] % mod;
    101             if(belong[tem] != N) continue;
    102             update(id[j], f[tem]);
    103         }
    104         for(int j = 0; j < cnt1; j++){
    105             int tem = path[j];
    106             if(belong[tem] != N || f[tem] > id[j]) f[tem] = id[j], belong[tem] = N;
    107         }
    108     }
    109     N++;
    110     for(int i = head[root]; i + 1; i = edge[i].next){
    111         int v = edge[i].to;
    112         if(vis[v]) continue;
    113         solve(v, sum[v]);
    114     }
    115 }
    116 
    117 int main(){
    118     init();
    119     while(~scanf("%d%I64d", &n, &K)){
    120         for(int i = 1; i <= n; i++) scanf("%I64d", &val[i]);
    121         memset(head, -1, sizeof head);
    122         memset(belong, -1, sizeof belong);
    123         memset(ans, -1, sizeof ans);
    124         memset(vis, 0, sizeof vis);
    125         N = 0;
    126         for(int i = 1, p, q; i < n; i++){
    127             scanf("%d%d", &p, &q);
    128             addEdge(p, q);
    129             addEdge(q, p);
    130         }
    131         N = 0;
    132         solve(1, n);
    133         if(ans[0] == -1) puts("No solution");
    134         else printf("%d %d
    ", ans[0], ans[1]);
    135     }
    136     return 0;
    137 }
    View Code
  • 相关阅读:
    android studio 汉化 个性化 美化 快速操作项目 目录
    Where should we fork this repository?
    剑指offer-链表中环的入口节点
    剑指offer-两个链表的第一个公共节点
    剑指offer-链表中倒数第k个结点
    算法导论-快速排序
    剑指offer-旋转数组的最小数字
    剑指offer-数组中出现次数超过一半的数字
    PAT1048. Find Coins(01背包问题动态规划解法)
    17网易-优雅的点
  • 原文地址:https://www.cnblogs.com/astoninfer/p/4746387.html
Copyright © 2011-2022 走看看