1986 Distance Queries //LCA+VECTOR 贼慢

本文介绍了一种高效的解决农场间距离查询问题的算法。该算法通过构建树状结构来快速计算任意两个农场之间的最短路径,适用于大规模的数据集。文章提供了完整的代码实现及样例输入输出。

Distance Queries
Time Limit: 2000MS Memory Limit: 30000K
Total Submissions: 3709 Accepted: 1316
Case Time Limit: 1000MS

Description

Farmer John's cows refused to run in his marathon since he chose a path much too long for their leisurely lifestyle. He therefore wants to find a path of a more reasonable length. The input to this problem consists of the same input as in "Navigation Nightmare",followed by a line containing a single integer K, followed by K "distance queries". Each distance query is a line of input containing two integers, giving the numbers of two farms between which FJ is interested in computing distance (measured in the length of the roads along the path between the two farms). Please answer FJ's distance queries as quickly as possible!

Input

* Lines 1..1+M: Same format as "Navigation Nightmare"

* Line 2+M: A single integer, K. 1 <= K <= 10,000

* Lines 3+M..2+M+K: Each line corresponds to a distance query and contains the indices of two farms.

Output

* Lines 1..K: For each distance query, output on a single line an integer giving the appropriate distance.

Sample Input

7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S
3
1 6
1 4
2 6

Sample Output

13
3
36

Hint

Farms 2 and 6 are 20+3+13=36 apart.

Source

 

 

#include<stdio.h>

#include<vector>

using namespace std;

const int MAX=40005;

struct node

{

    node(int vv=0,int vval=0):v(vv),val(vval) {}

    int v,val;

};

 

int f[MAX],vis[MAX];

 

vector<node> tree[2*MAX],Qes[2*MAX];

int d[MAX],res[MAX];

 

void init(int n)

{

    for(int i=1; i<=n; i++)

    {

        f[i]=i;//用于并查集记录父亲节点

        vis[i]=0;//是否被访问

        tree[i].clear();//清空

        Qes[i].clear();

        res[i]=0;

    }

}

 

int find(int n)   //查找函数,并压缩路径

{

    if(n!=f[n]) f[n]=find(f[n]);

    return f[n];

}

int Union(int x,int y)  //合并函数,如果属于同一分支则返回0,成功合并返回1

{

    int a=find(x),b=find(y);

    f[y]=x;

    return b;

}

 

void LCA(int u,int dis)

{

    d[u]=dis;

    vis[u]=1;

    int size=tree[u].size();

    for(int i=0; i<size; i++)

    if(!vis[tree[u][i].v])

    {

        LCA(tree[u][i].v,dis+tree[u][i].val);

        Union(u,tree[u][i].v);

    }

 

    size=Qes[u].size();

    for(int i=0; i<size; i++)  //如果已经访问了问题节点,就可以返回结果了.

    {

        if(vis[Qes[u][i].v])

        {

            int p=find(Qes[u][i].v);

            res[Qes[u][i].val]=dis+d[Qes[u][i].v]-2*d[p];

        }

    }

}

int main()

{

    int n,m;

    while(scanf("%d%d",&n,&m)!=EOF)

    {

        init(n);

        int s,t,c;

        char ch;

        for(int i=1; i<=m; i++)

        {

            scanf(" %d %d %d %c",&s,&t,&c,&ch);

            tree[s].push_back(node(t,c));

            tree[t].push_back(node(s,c));

        }

        int k;

        scanf("%d",&k);

        for(int i=1;i<=k;i++)

        {

            scanf("%d%d",&s,&t);//这里可以输入多组询问

            Qes[s].push_back(node(t,i));//相当于询问两次

            Qes[t].push_back(node(s,i));

        }

        LCA(1,0);

        for(int i=1;i<=k;i++)  printf("%d/n",res[i]);

    }

    return 0;

}

//#pragma GCC optimize(2,3,“Ofast”,“inline”, “-ffast-math”) //#pragma GCC target(“avx,sse2,sse3,sse4,mmx”) #include #include #include #include #include #include #include #include #include<unordered_map> #include #include #include #include #include #include #include #define fi first #define se second #define pb push_back #define y1 hsduaishxu #define mkp make_pair using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,int> pli; typedef pair<int,ll> pil; typedef pair<ll,ll> pll; typedef unsigned int uint; typedef vector vpii; typedef int128 i128; const int maxn=1000005; const ll mod=1000000007; inline int Min(int x,int y){return x<y?x:y;} inline int Max(int x,int y){return x>y?x:y;} inline ll Min(ll x,ll y){return x<y?x:y;} inline ll Max(ll x,ll y){return x>y?x:y;} inline void ad(int &x,int y,int z){x=y+z;if(x>=mod) x-=mod;} inline void ad(ll &x,ll y,ll z){x=y+z;if(x>=mod) x-=mod;} inline void ad(int &x,int y){x+=y;if(x>=mod) x-=mod;} inline void ad(int &x,ll y){x+=y;if(x>=mod) x-=mod;} inline void ad(ll &x,ll y){x+=y;if(x>=mod) x-=mod;} inline void siu(int &x,int y,int z){x=y-z;if(x<0) x+=mod;} inline void siu(int &x,int y){x-=y;if(x<0) x+=mod;} inline void siu(ll &x,ll y){x-=y;if(x<0) x+=mod;} inline ll myabs(ll x){return x<0?-x:x;} inline void tmn(int &x,int y){if(y<x) x=y;} inline void tmx(int &x,int y){if(y>x) x=y;} inline void tmn(ll &x,ll y){if(y<x) x=y;} inline void tmx(ll &x,ll y){if(y>x) x=y;} ll qpow(ll aa,ll bb){ll res=1;while(bb){if(bb&1) res=resaa%mod;aa=aaaa%mod;bb>>=1;}return res;} ll qpow(ll aa,ll bb,ll md){ll res=1;while(bb){if(bb&1) res=(i128)resaa%md;aa=(i128)aaaa%md;bb>>=1;}return res;} inline ll Inv(ll x,ll md){return qpow(x,md-2,md);} inline ll Inv(ll x){return qpow(x,mod-2);} int ,; int n,k; int p[maxn],q[maxn]; ll ans; vector g[maxn],h[maxn]; int r1,r2; int siz[maxn],dfn[maxn],dfscnt; void dfs(int u) { siz[u]=1;dfn[u]=dfscnt; for(auto v:g[u]) dfs(v),siz[u]+=siz[v]; } struct bit { int c[maxn]; void clr() { for(int i=1;i<=n;i) c[i]=0; } int lowbit(int x){return x&(-x);} void ad(int x,int k){while(x<=n){c[x]+=k;x+=lowbit(x);}} int qry(int x){int res=0;while(x>=1){res+=c[x];x-=lowbit(x);}return res;} }T1,T2; int F[maxn],st[maxn],tp,sz[maxn],son[maxn]; vector e[maxn]; void dfs1(int u) { st[tp]=u;e[u].clear(); if(tp>k) F[u]=st[tp-k]; else F[u]=0; if(F[u]) e[F[u]].push_back(u); sz[u]=1;son[u]=0; for(auto v:h[u]) { dfs1(v); if(sz[v]>sz[son[u]]) son[u]=v; sz[u]+=sz[v]; } tp–; } void ins(int x,int k) { T1.ad(dfn[x],k);T1.ad(dfn[x]+siz[x],-k); T2.ad(dfn[x],k); } int qry(int x) { return T1.qry(dfn[x])+T2.qry(dfn[x]+siz[x]-1)-T2.qry(dfn[x]-1); } void dfs3(int u,int ty) { for(auto v:e[u]) { if(ty1) ans+=qry(v); else if(ty3) ins(v,-1); else if(ty==2) ins(v,1); } for(auto v:h[u]) dfs3(v,ty); } void dfs2(int u,int ty) { for(auto v:h[u]) if(v!=son[u]) dfs2(v,0); if(son[u]) { dfs2(son[u],1); for(auto v:h[u]) if(v!=son[u]) dfs3(v,1),dfs3(v,2); } for(auto v:e[u]) ins(v,1); if(!ty) dfs3(u,3); } void cal() { dfscnt=0;dfs(r1); T1.clr();T2.clr(); tp=0;dfs1(r2); dfs2(r2,0); } void solve() { cin>>n>>k; for(int i=1;i<=n;i) cin>>p[i]; for(int i=1;i<=n;i++) cin>>q[i]; for(int i=1;i<=n;i++) { if(!p[i]) r1=i; else g[p[i]].push_back(i); if(!q[i]) r2=i; else h[q[i]].push_back(i); } cal(); for(int i=1;i<=n;i++) swap(p[i],q[i]),swap(g[i],h[i]);swap(r1,r2); cal(); cout<<ans<<“\n”; } signed main() { freopen(“D.in”,“r”,stdin); freopen(“D.out”,“w”,stdout); ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); =1; //cin>>; while(–) { solve(); } return 0; } //by cristiano ronaldo dos santos aveiro #include <bits/stdc++.h> using namespace std; typedef long long ll; #define rep(i,s,t) for(register ll i = s;i <= t;++i) #define per(i,t,s) for(register ll i = t;i >= s;–i) const ll N = 1e6 + 5; ll n; ll k; ll rt1; ll rt2; ll top; ll idx; ll ans; ll p[N] = {}; ll q[N] = {}; ll fa[N] = {}; ll st[N] = {}; ll sz[N] = {}; ll siz[N] = {}; ll dfn[N] = {}; ll son[N] = {}; vector g[N]; vector g1[N]; vector g2[N]; class binary_indexed_tree { private: ll t[N] = {}; public: inline void init() { memset(t,0,sizeof(t)); } inline ll lowbit(ll x) { return x & (-x); } inline void upd(ll x,ll k) { while(x <= n) { t[x] += k; x += lowbit(x); } } inline ll qry(ll x) { ll ans = 0; while(x) { ans += t[x]; x -= lowbit(x); } return ans; } }; binary_indexed_tree t1; binary_indexed_tree t2; inline ll read() { ll x = 0; ll y = 1; char c = getchar(); while(c < ‘0’ || c > ‘9’) { if(c == ‘-’) y = -y; c = getchar(); } while(c >= ‘0’ && c <= ‘9’) { x = (x << 3) + (x << 1) + (c ^ ‘0’); c = getchar(); } return x * y; } inline void write(ll x) { if(x < 0) { putchar(‘-’); write(-x); return; } if(x > 9) write(x / 10); putchar(x % 10 + ‘0’); } inline void dfs(ll u) { siz[u] = 1; dfn[u] = ++idx; for(register auto v : g1[u]) { dfs(v); siz[u] += siz[v]; } } inline void dfs1(ll u) { st[++top] = u; g[u].clear(); if(top > k) fa[u] = st[top - k]; else fa[u] = 0; if(fa[u]) g[fa[u]].push_back(u); sz[u] = 1; son[u] = 0; for(auto v : g2[u]) { dfs1(v); if(sz[v] > sz[son[u]]) son[u] = v; sz[u] += sz[v]; } top–; } inline void ins(ll x,ll k) { t1.upd(dfn[x],k); t1.upd(dfn[x] + siz[x],-k); t2.upd(dfn[x],k); } inline ll query(ll x) { return t1.qry(dfn[x]) + t2.qry(dfn[x] + siz[x] - 1) - t2.qry(dfn[x] - 1); } inline void dfs3(ll u,ll k) { for(auto v : g[u]) { if(k == 1) ans += query(v); else if(k == 2) ins(v,1); else if(k == 3) ins(v,-1); } for(auto v : g2[u]) dfs3(v,k); } inline void dfs2(ll u,ll k) { for(auto v : g2[u]) if(v != son[u]) dfs2(v,0); if(son[u]) { dfs2(son[u],1); for(auto v : g2[u]) { if(v != son[u]) { dfs3(v,1); dfs3(v,2); } } } for(register auto v : g[u]) ins(v,1); if(!k) dfs3(u,3); } int main() { freopen(“D.in”,“r”,stdin); freopen(“D.out”,“w”,stdout); n = read(); k = read(); rep(i,1,n) p[i] = read(); rep(i,1,n) q[i] = read(); rep(i,1,n) { if(!p[i]) rt1 = i; else g1[p[i]].push_back(i); if(!q[i]) rt2 = i; else g2[q[i]].push_back(i); } idx = 0; dfs(rt1); t1.init(); t2.init(); top = 0; dfs1(rt2); dfs2(rt2,0); rep(i,1,n) { swap(p[i],q[i]); swap(g1[i],g2[i]); swap(rt1,rt2); } idx = 0; dfs(rt1); t1.init(); t2.init(); top = 0; dfs1(rt2); dfs2(rt2,0); write(ans); fclose(stdin); fclose(stdout); return 0; }针对以下问题,上述两段代码的功能有什么不同,请指出并修正第二段代码,使得第二段代码功能与第一段代码功能完全等价小丁的树 题目描述 小丁拥有两棵均具有 n n 个顶点,编号集合为 { 1 , 2 , ⋯   , n } {1,2,⋯,n} 的有根树 T 1 , T 2 T 1 ​ ,T 2 ​ ,现在他需要计算这两棵树的相似程度。 为了计算,小丁定义了对于一棵树 T T 和 T T 上两个不同顶点 u , v u,v 的距离函数 d T ( u , v ) d T ​ (u,v),其定义为 u , v u,v 两个点距离成为祖先关系有多近,具体来说,对于所有在 T T 上为祖先关系的点对 ( u ′ , v ′ ) (u ′ ,v ′ ), dis ⁡ ( u , u ′ ) + dis ⁡ ( v , v ′ ) dis(u,u ′ )+dis(v,v ′ ) 的最小值即为 d T ( u , v ) d T ​ (u,v) 的值,其中 dis ⁡ ( u , v ) dis(u,v) 表示 u , v u,v 在树 T T 上的唯一简单路径包含的边数,即 u , v u,v 的距离。 点对 ( u ′ , v ′ ) (u ′ ,v ′ ) 为祖先关系,当且仅当 u ′ u ′ 是 v ′ v ′ 的祖先或 v ′ v ′ 是 u ′ u ′ 的祖先。(注意,每个点都是自己的祖先) 小丁心里还有一个参数 k k,如果节点对 ( u , v ) (u,v) 满足以下条件,称之为不相似的节点对: 1 ≤ u < v ≤ n 1≤u<v≤n " d T 1 ( u , v ) 0 d T 1 ​ ​ (u,v)=0 且 d T 2 ( u , v ) k d T 2 ​ ​ (u,v)>k“ 或 " d T 2 ( u , v ) 0 d T 2 ​ ​ (u,v)=0 且 d T 1 ( u , v ) k d T 1 ​ ​ (u,v)>k​“ 小丁认为,不相似的节点对越多, T 1 T 1 ​ 和 T 2 T 2 ​ 就越不相似,你能告诉他总共有多少不相似的节点对吗? 输入格式 第一行两个整数 n , k n,k,表示 T 1 T 1 ​ 和 T 2 T 2 ​ 的节点数和参数 k k。 第二行 n n 个正整数 p 1 , p 2 , ⋯   , p n p 1 ​ ,p 2 ​ ,⋯,p n ​ , T 1 T 1 ​ 中节点 i i 的父节点为 p i p i ​ ,特别的,若 p i 0 p i ​ =0,则 i i 是 T 1 T 1 ​ 的根。 第三行 n n 个正整数 q 1 , q 2 , ⋯   , q n q 1 ​ ,q 2 ​ ,⋯,q n ​ , T 2 T 2 ​ 中节点 i i 的父节点为 q i q i ​ ,特别的,若 q i 0 q i ​ =0,则 i i 是 T 2 T 2 ​ 的根。 输出格式 一行一个整数,表示不相似的节点对总数。 样例 1 输入 5 0 0 1 1 2 3 5 3 1 1 0 样例 1 输出 4 样例 1 解释 ( 2 , 3 ) , ( 2 , 4 ) , ( 2 , 5 ) , ( 4 , 5 ) (2,3),(2,4),(2,5),(4,5) 为不相似的节点对。 其余样例见下发文件。 数据规模与约定 对于所有数据, 1 ≤ n ≤ 2 × 10 5 , 0 ≤ k < n , 0 ≤ p i , q i ≤ n 1≤n≤2×10 5 ,0≤k<n,0≤p i ​ ,q i ​ ≤n,且由 p i , q i p i ​ ,q i ​ 形成的是一棵 n n 个节点的有根树。 本题采用捆绑评测,你只有通过了一个子任务中所有测试点才能得到该子任务的分数。 Subtask 1(10pts): 1 ≤ n ≤ 100 1≤n≤100。 Subtask 2(20pts): 1 ≤ n ≤ 3000 1≤n≤3000。 Subtask 3(20pts): k 0 k=0。 Subtask 4(10pts): 0 ≤ k ≤ 20 0≤k≤20。 Subtask 5(40pts):无特殊限制。
07-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值