題意簡述
給你一個 個點的邊帶權的樹,還有 個新增的修建計劃,以及 個詢問。每一個詢問的格式是:給定 ,問你,如果動用 之間的修建計劃,從 到 的路徑中,邊權異或和最小是多少?
詢問之間是獨立的,在某一個詢問里加入的修建計劃,詢問完就會拆掉。並且修建計劃保證不是樹上原來就有的邊。
,所有的邊權(樹上和修建計劃) 。對於每個詢問,,並且。
思路
由 bzoj 2115
的結論得,一張圖上從 到 的路徑的異或和,可以由另外一條路徑的異或和,異或上幾個環的異或和得到。
然後我們珂以先取初始值爲 到 樹上路徑的異或和,然後在把所有環的異或和放到線性基裏,求最小異或和。
本題還限制了只能動用 之間的修建計劃。那就按 排個序,對於每個位置 ,記錄所有 的詢問。然後在插入線性基的時候,順便維護上修建計劃的編號。對於每個詢問,我們只考慮 的修建計劃,不用考慮動用 $>r $的修建計劃的問題,只要滿足修建計劃的編號 即珂。線性基求最小異或和的時候,順便維護下即珂。
代碼
#include <bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
#define N 355555
#define F(i,l,r) for(int i=l;i<=r;++i)
#define D(i,r,l) for(int i=r;i>=l;--i)
#define Fs(i,l,r,c) for(int i=l;i<=r;c)
#define Ds(i,r,l,c) for(int i=r;i>=l;c)
#define MEM(x,a) memset(x,a,sizeof(x))
#define FK(x) MEM(x,0)
#define Tra(i,u) for(int i=G.Start(u),__v=G.To(i);~i;i=G.Next(i),__v=G.To(i))
#define p_b push_back
#define sz(a) ((int)a.size())
#define iter(a,p) (a.begin()+p)
void R1(int &x)
{
x=0;char c=getchar();int f=1;
while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=(f==1)?x:-x;
}
void Rd(int cnt,...)
{
va_list args;
va_start(args,cnt);
F(i,1,cnt)
{
int* x=va_arg(args,int*);R1(*x);
}
va_end(args);
}
class Graph
{
public:
int head[N];
int EdgeCount;
struct Edge
{
int To,Label,Next;
}Ed[N<<1];
void clear(int _V=N,int _E=N<<1)
{
memset(Ed,-1,sizeof(Edge)*(_E));
memset(head,-1,sizeof(int)*(_V));
EdgeCount=-1;
}
void AddEdge(int u,int v,int w=1)
{
Ed[++EdgeCount]=(Edge){v,w,head[u]};
head[u]=EdgeCount;
}
void Add2(int u,int v,int w=1) {AddEdge(u,v,w);AddEdge(v,u,w);}
int Start(int u) {return head[u];}
int To(int u){return Ed[u].To;}
int Label(int u){return Ed[u].Label;}
int Next(int u){return Ed[u].Next;}
}G;
int n,m,q;
void Input()
{
Rd(3,&n,&m,&q);
G.clear();
F(i,1,n-1)
{
int u,v,w;Rd(3,&u,&v,&w);
G.Add2(u,v,w);
}
}
int d[N];
void DFS(int u,int f) //先預處理出每個點到根的異或和:d[i]
{
Tra(i,u)
{int v=__v;
if (v!=f)
{
d[v]=d[u]^G.Label(i);
DFS(v,u);
}
}
}
int w[N];
int l[N],r[N];
int p[32],id[32]; //p是線性基,id是線性基順便維護的修建計劃編號
vector<int> pos[N];
int ans[N];
void Soviet()
{
DFS(1,1);
F(i,1,m)
{
int u,v,len;Rd(3,&u,&v,&len);
w[i]=d[u]^d[v]^len; //第i個修建計劃從u到v,那就會產生一個環,這個環的異或和爲:u到v樹上路徑的異或和,再以後上修建計劃的邊權
}
F(i,1,q)
{
int s,t;Rd(2,&s,&t);
ans[i]=d[s]^d[t]; //初始答案就是s到t的樹上路徑異或
Rd(2,&l[i],&r[i]);
pos[r[i]].p_b(i); //離線,按r排序,把r相同的詢問一塊考慮
}
F(t,1,m)
{
int x=w[t],r=t;
D(i,30,0) if ((x>>i)&1)
{
if (!p[i]){p[i]=x;id[i]=r;break;}
if (id[i]<r) swap(p[i],x),swap(id[i],r);
x^=p[i];
} //插入線性基的時候順便維護編號
F(k,0,sz(pos[t])-1)
{int v=pos[t][k];
D(i,30,0)
{
if (id[i]>=l[v]) ans[v]=min(ans[v],ans[v]^p[i]);
//在考慮編號>=l的情況下,求最小異或和
}
}
}
F(i,1,q) printf("%d\n",ans[i]);
}
#define Flan void
Flan IsMyWife()
{
Input();
Soviet();
}
}
int main()
{
Flandre_Scarlet::IsMyWife();
getchar();getchar();
return 0;
}