思路:
1、一种海拔 30’
求最短路。
询问时,海拔==0,输出0;否则输出dist[v]。
2、链 15’
离散化。
预处理出不同海拔、每个点开始到起点的答案,查表输出。
3、树 10
树上倍增。
4、
kruskal重构树+树上倍增。
做kruskal时,在并查集路径压缩时,同时存下树的心态。
即,在最小生成树连边时,新建一个节点,权为边权,作为两节点的父节点。
然后再在重构树上倍增求解。
代码:
#include<bits/stdc++.h>
using namespace std;
#define read(x) scanf("%d",&x)
#define ll long long
#define inf (1LL<<60)
struct Edge{
int x,y,w,v;
Edge(){}
Edge(int xx,int yy,int ww,int vv) {x=xx,y=yy,w=ww,v=vv;}
bool operator < (const Edge& oth) const {
return v>oth.v;
}
};
struct Pair{
ll x,y;
Pair(){}
Pair(ll xx,ll yy) {x=xx,y=yy;}
bool operator < (const Pair& oth) const {return y>oth.y;}
};
#define maxnall 200000
#define maxmall 400000
int n,m;
int X[maxmall+5],Y[maxmall+5],W[maxmall+5],V[maxmall+5];
int Q,K,S;
#define maxn30 200000
#define maxm30 400000
vector<Edge> g30[maxn30+5];
ll dist[maxn30+5];
bool vis[maxn30+5];
priority_queue<Pair> que,emp;
void MakeClean30() {
for(int i=1;i<=n;i++) g30[i].clear();
dist[1]=0;for(int i=2;i<=n;i++) dist[i]=inf;
memset(vis,0,sizeof(vis));
que=emp;
}
void dijkstra30() {
que.push(Pair(1,0));
while(!que.empty()) {
int h=que.top().x;que.pop();
if(vis[h]) continue;vis[h]=true;
for(int i=0;i<g30[h].size();i++) {
Edge y=g30[h][i];
if(dist[y.y]>dist[h]+y.w) {
dist[y.y]=dist[h]+y.w;
que.push(Pair(y.y,dist[y.y]));
}
}
}
}
void slv30() {
for(int i=1;i<=m;i++) {
g30[X[i]].push_back(Edge(X[i],Y[i],W[i],V[i]));
g30[Y[i]].push_back(Edge(Y[i],X[i],W[i],V[i]));
}
dijkstra30();
for(int i=1;i<=Q;i++) {
int x,v;
read(x),read(v);
if(v>=1) printf("%lld\n",dist[x]);
else printf("0\n");
}
}
#define maxnlink 1500
#define maxwlink 4000
#define maxQlink 100000
int wlink[maxnlink+5],vlink[maxnlink+5];
int Qn[maxQlink+5],Qv[maxQlink+5];
map<int,int> mplink;int cnt;
ll flink[maxnlink+5][maxwlink+5];
ll slink[maxnlink+5];
void MakeCleanlink() {
mplink.clear(),cnt=0;
memset(flink,0,sizeof(flink));
memset(slink,0,sizeof(slink));
}
void slvlink() {
for(int i=1;i<n;i++) {
wlink[Y[i]]=W[i],vlink[Y[i]]=V[i];
mplink[vlink[Y[i]]]=true;
}
for(int i=1;i<=Q;i++) {
read(Qn[i]),read(Qv[i]);
mplink[Qv[i]]=true;
}
for(map<int,int>::iterator it=mplink.begin();it!=mplink.end();++it) {
mplink[it->first]=++cnt;
}
for(int i=2;i<=n;i++) vlink[i]=mplink[vlink[i]];
for(int i=1;i<=Q;i++) Qv[i]=mplink[Qv[i]];
for(int i=2;i<=n;i++) slink[i]=wlink[i]+slink[i-1];
for(int d=1;d<=cnt;d++) {
int lstd=0;
for(int i=2;i<=n;i++) {
if(vlink[i]<=d) lstd=i;
flink[i][d]=slink[lstd];
}
}
for(int i=1;i<=Q;i++) {
printf("%lld\n",flink[Qn[i]][Qv[i]]);
}
}
#define maxn 200000
#define maxm 800000
#define intinf (1<<30)
struct Node{
ll d;
int x,fa;
int ch1,ch2;
Node() {}
};
vector<Edge> e;
int c;
Node tr[maxm+5];
int fa[maxm+5];
int find(int x) {
if(fa[x]) return fa[x]=find(fa[x]);
else return x;
}
void MakeClean() {
MakeClean30();
e.clear(),c=0;
memset(tr,0,sizeof(tr));
memset(fa,0,sizeof(fa));
}
int anc[maxm+5][30];
int srch(int x,int u) {
for(int i=25;i>=0;i--) {
if(!anc[x][i]) continue;
if(tr[anc[x][i]].x>u) x=anc[x][i];
}
return x;
}
void dfs(int x) {
anc[x][0]=tr[x].fa;
for(int i=1;i<=25;i++) {
anc[x][i]=anc[anc[x][i-1]][i-1];
}
if(tr[x].ch1) dfs(tr[x].ch1);
if(tr[x].ch2) dfs(tr[x].ch2);
}
void slv() {
for(int i=1;i<=m;i++) e.push_back(Edge(X[i],Y[i],W[i],V[i]));
sort(e.begin(),e.end());
for(int i=1;i<=m;i++) {
g30[X[i]].push_back(Edge(X[i],Y[i],W[i],V[i]));
g30[Y[i]].push_back(Edge(Y[i],X[i],W[i],V[i]));
}
dijkstra30();
for(int i=1;i<=n;i++) {tr[++c].x=intinf;tr[c].d=dist[c];}
for(int i=0;i<e.size();i++) {
Edge x=e[i];
int fa1=find(e[i].x),fa2=find(e[i].y);
if(fa1==fa2) continue;
tr[++c].x=min(min(tr[fa1].x,tr[fa2].x),x.v);
tr[c].d=min(tr[fa1].d,tr[fa2].d);
tr[c].ch1=fa1,tr[c].ch2=fa2;
tr[fa1].fa=c,tr[fa2].fa=c;
fa[fa1]=c,fa[fa2]=c;
}
dfs(c);
int lst=0;
for(int i=1;i<=Q;i++) {
int x,v;
read(x),read(v);
x=(x+K*lst-1)%n+1,v=(v+K*lst)%(S+1);
int u=srch(x,v);
printf("%lld\n",lst=tr[u].d);
}
}
int main() {
int T;
read(T);
while(T--) {
bool is30=true;
read(n),read(m);
for(int i=1;i<=m;i++) {
read(X[i]),read(Y[i]),read(W[i]),read(V[i]);
if(V[i]!=1) is30=false;
}
read(Q),read(K),read(S);
if(is30) {
MakeClean30();
slv30();
} else if(n<=maxnlink&&m==n-1) {
MakeCleanlink();
slvlink();
} else {
MakeClean();
slv();
}
}
return 0;
}