hdu4812 D Tree 点分治

这里要求输出字典序最小的两个点,就不能像之前那样容斥了,只能直接搞了。

直接搞的话,需要避开n^2,由于这里是等式,显然应该考虑hash映射。从前往后依次枚举计算每棵子树,对于每个子树结点,快速从前面已经计算过的子树中找到答案更新就可以了。

很简单的东西,只是难以用文字解释得清楚。大概一般点分治不用容斥直接搞大多是这样干吧。

#pragma comment(linker,"/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<map>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1e9+10;

template<class T>
inline void scan(T &ret)
{
    char c=getchar();
    while(!isdigit(c)) c=getchar();
    ret=c-‘0‘;
    while(isdigit(c=getchar())) ret=ret*10+c-‘0‘;
}

inline void out(int a)
{
    if(a>9) out(a/10);
    putchar(a%10+‘0‘);
}

const ll MOD=1e6+3;
int N,K;
int val[maxn];
//vector<int> G[maxn];
int u,v;
int ans1,ans2;
int id[maxn];
int d[maxn],dn;
ll s[maxn];
bool vis[maxn];
int rt,balance;
int Inv[maxn];
int e[maxn],tot;
int first[maxn],Next[maxn];

void Init()
{
    tot=0;
    memset(first,-1,sizeof(first));
}

void addedge(int u,int v)
{
    e[++tot]=v;
    Next[tot]=first[u];
    first[u]=tot;
}

ll mul(ll a,ll b,ll MOD)
{
    return (a*b)%MOD;
}

ll qpow(ll n,ll k,ll p)
{
    ll res=1;
    while(k){
        if(k&1) res=(res*n)%p;
        n=(n*n)%p;
        k>>=1;
    }
    return res;
}

void dfs_d(int u,int f,ll dep)
{
    d[++dn]=u;
    s[u]=dep;
    //for(int i=0;i<G[u].size();i++){
    for(int p=first[u];~p;p=Next[p]){
        int v=e[p];
        if(v==f||vis[v]) continue;
        dfs_d(v,u,mul(dep,val[v],MOD));
    }
}

ll inv(ll a,ll p)
{
    return qpow(a,p-2,p);
}

void update(int x,int y)
{
    if(x>y) swap(x,y);
    if(x<ans1) ans1=x,ans2=y;
    else if(x==ans1){
        if(y<ans2) ans1=x,ans2=y;
    }
}

int get_rt(int u,int f,int sz)
{
    int cnt=1,balance1=0;
    for(int p=first[u];~p;p=Next[p]){
        int v=e[p];
        if(v==f||vis[v]) continue;
        int tmp=get_rt(v,u,sz);
        cnt+=tmp;
        balance1=max(balance1,tmp);
    }
    balance1=max(balance1,sz-cnt);
    if(balance1<balance){
        balance=balance1;
        rt=u;
    }
    return cnt;
}

void cls_id(int u,int f)
{
    id[s[u]]=0;
    //for(int i=0;i<G[u].size();i++){
    for(int p=first[u];~p;p=Next[p]){
        int v=e[p];
        if(v==f||vis[v]) continue;
        cls_id(v,u);
    }
}

void solve(int u)
{
    rt=u,balance=INF;
    int sz=get_rt(u,0,N);
    rt=u,balance=INF;
    get_rt(u,0,sz);
    u=rt;
    //cout<<"u="<<u<<endl;
    vis[u]=1;
    id[val[u]]=u;
    s[u]=val[u];
    //for(int i=0;i<G[u].size();i++){
    for(int p=first[u];~p;p=Next[p]){
        int v=e[p];
        if(vis[v]) continue;
        dn=0;
        dfs_d(v,u,mul(val[u],val[v],MOD));
        //cout<<" v="<<v<<" dn="<<dn<<endl;
        //REP(j,1,dn) cout<<d[j]<<"_";cout<<endl;
        int idx,x,idy;
        REP(j,1,dn){
            idx=d[j],x=s[idx];
            idy=id[mul(mul(K,val[u],MOD),Inv[x],MOD)];
            if(idy) update(idx,idy);
        }
        REP(j,1,dn){
            idx=d[j],x=s[idx];
            if(id[x]) id[x]=min(id[x],idx);
            else id[x]=idx;
        }
    }
    cls_id(u,0);
    //for(int i=0;i<G[u].size();i++){
    for(int p=first[u];~p;p=Next[p]){
        int v=e[p];
        if(vis[v]) continue;
        solve(v);
    }
}

void play()
{
    freopen("in.txt","w",stdout);
    int n=10000,k=120;
    cout<<n<<" "<<k<<endl;
    REP(i,1,n) cout<<i<<" ";cout<<endl;
    REP(i,1,n-1){
        cout<<i<<" "<<i+1<<endl;
    }
}

void Init_inv()
{
    REP(i,0,MOD-1) Inv[i]=inv(i,MOD);
}

int main()
{
    //play();return 0;
    freopen("in.txt","r",stdin);
    Init_inv();
    while(~scanf("%d%d",&N,&K)){
        Init();
        REP(i,1,N) scan(val[i]),val[i]%=MOD;
        REP(i,1,N-1){
            //scanf("%d%d",&u,&v);
            scan(u);scan(v);
            addedge(u,v);
            addedge(v,u);
        }
        ans1=ans2=INF;
        MS0(vis);MS0(id);
        solve(1);
        if(ans1==INF) puts("No solution");
        else{ //printf("%d %d\n",ans1,ans2);
            out(ans1);
            putchar(‘ ‘);
            out(ans2);
            putchar(‘\n‘);
        }
    }
    return 0;
}

TLE了几次,以为是算法问题,看标程都加了输入输出挂,我也加了试交一下,过了。。。是在下输了。。。

时间: 2024-10-18 15:38:49

hdu4812 D Tree 点分治的相关文章

[LeetCode] Convert Sorted List to Binary Search Tree(分治)

Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST. 方法:为了使BST高度平衡,要找链表中的中值作为当前根节点. /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) :

HDU4812 D Tree(树的点分治)

题目大概说给一棵有点权的树,输出字典序最小的点对,使这两点间路径上点权的乘积模1000003的结果为k. 树的点分治搞了.因为是点权过根的两条路径的LCA会被重复统计,而注意到1000003是质数,所以这个用乘法逆元搞一下就OK了.还有要注意“治”的各个实现,把时间复杂度“控制”在O(nlogn). WA了几次,WA在漏了点到子树根的路径,还有每次分治忘了清空数组. 1 #include<cstdio> 2 #include<cstring> 3 #include<algor

【点分治】【乘法逆元】hdu4812 D Tree

思路比较裸,但是要把答案存到哈希表里面,这里需要一定技巧,否则会被K=1且点权全是1的数据卡飞.预处理乘法逆元.TLE了一天.换了种点分治的姿势…… #pragma comment(linker,"/STACK:102400000,102400000") #include<cstdio> #include<algorithm> #include<cstring> using namespace std; int Res;char C; inline

poj 1744 tree 树分治

Tree Time Limit: 1000MS   Memory Limit: 30000K       Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dist(u,v)=The min distance between node u and v. Give an integer k,for every pair (u,v) of ve

POJ 1741 Tree ——点分治

[题目分析] 这貌似是做过第三道以Tree命名的题目了. 听说树分治的代码都很长,一直吓得不敢写,有生之年终于切掉这题. 点分治模板题目.自己YY了好久才写出来. 然后1A了,开心o(* ̄▽ ̄*)ブ [代码] #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define maxn 20005 #define inf 0x3f3f3f3f using

【BZOJ2870】最长道路tree 点分治+树状数组

[BZOJ2870]最长道路tree Description H城很大,有N个路口(从1到N编号),路口之间有N-1边,使得任意两个路口都能互相到达,这些道路的长度我们视作一样.每个路口都有很多车辆来往,所以每个路口i都有一个拥挤程度v[i],我们认为从路口s走到路口t的痛苦程度为s到t的路径上拥挤程度的最小值,乘上这条路径上的路口个数所得的积.现在请你求出痛苦程度最大的一条路径,你只需输出这个痛苦程度. 简化版描述: 给定一棵N个点的树,求树上一条链使得链的长度乘链上所有点中的最小权值所得的积

【BZOJ-1468】Tree 树分治

1468: Tree Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1025  Solved: 534[Submit][Status][Discuss] Description 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K Input N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k Output 一行,有多少对点之间的距离小于等于k Sample Input 7 1 6 13 6

HDU 4812 D Tree 树分治+逆元处理

D Tree Problem Description There is a skyscraping tree standing on the playground of Nanjing University of Science and Technology. On each branch of the tree is an integer (The tree can be treated as a connected graph with N vertices, while each bran

【CodeForces】914 E. Palindromes in a Tree 点分治

[题目]E. Palindromes in a Tree [题意]给定一棵树,每个点都有一个a~t的字符,一条路径回文定义为路径上的字符存在一个排列构成回文串,求经过每个点的回文路径数.n<=2*10^5. [算法]点分治 [题解]状压20位的二进制表示一条路径的字符状态,点分治过程中维护扫描过的路径只须维护状态桶数组,t[i]表示前面状态为i的路径条数. 合并:考虑当前状态为j,要使合并的状态满足条件即i^j=1<<k(0<=k<20)或i^j=0,移项得i=j^(1<