icpc网络赛 J Red-Black Paths离线,前缀异或,重构图,暴力剪枝
Posted goto_1600
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了icpc网络赛 J Red-Black Paths离线,前缀异或,重构图,暴力剪枝相关的知识,希望对你有一定的参考价值。
Link
题意:
给定一个图,按照时间顺序建图,给点染成红黑色,求相邻两次询问之间新增的红黑路的价值的异或和,红黑路的价值指的是路上每个点的权值乘以长度。数据保证所有红黑路长度<=10。保证所有红黑路<=5000000
思路:
由于可以离线,我们可以按照时间序来存储图,由于我们只要红开头,黑结尾的,对于其他的我们可以减枝,把无关紧要的点去掉,一看复杂度,
∑
红
黑
路
<
=
5000000
\\sum红黑路<=5000000
∑红黑路<=5000000,就算每次暴力搜索红黑路也只有
O
(
10
)
O(10)
O(10) 5e7的复杂度绰绰有余,启发我们构造新图,只对有用的点连边,然后用时间序来保证答案的正确性,维护个前缀异或的答案,当我们询问两个询问之间的操作,也就是区间异或值查询,不再赘述。
代码:
//#pragma GCC target("avx")
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
//#pragma GCC optimize("Ofast")
// created by myq
#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
#define x first
#define y second
typedef pair<int,int> pii;
const int N = 400010,M=1000010;
const int mod=998244353;
inline int read()
{
int res=0;
int f=1;
char c=getchar();
while(c>'9' ||c<'0')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
res=(res<<3)+(res<<1)+c-'0';
}
return res;
}
int h[N],e[M],ne[M],w[M],idx;
bool flag[N];
int red[N];
int black[N];
ll ans[N];
bool vis[N];
vector<int>q;
void add(int a,int b,int c){
e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
void dfs(int x){
if(black[x])
flag[x]=true;
vis[x]=true;
for(int i=h[x];~i;i=ne[i]){
int j=e[i];
if(vis[j]){
flag[x]|=flag[j];
continue;
}
dfs(j);
flag[x]|=flag[j];
}
}
struct node{
int a;
int b;
int c;
}edge[M];
int cnt;
void rebuild(){
idx=0;
memset(h,-1,sizeof h);
for(int i=0;i<cnt;i++){
int a=edge[i].a;
int b=edge[i].b;
int w=edge[i].c;
// cout<<a<<" "<<b<<endl;
if(flag[a]&flag[b])
add(a,b,w);
}
}
void dfss(int u,int tm,ll sum,int dep){
if(black[u])
{
ans[max(tm,black[u])]^=sum;
}
for(int i=h[u];~i;i=ne[i]){
int j=e[i];
dfss(j,max(tm,w[i]),sum+1ll*dep*j,dep+1);
}
}
vector<int>Red;
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
memset(h,-1,sizeof h);
int n;
cin>>n;
cnt=0;
for(int i=1;i<=n;i++){
int op;
cin>>op;
if(op==1){
int u,v,w;
cin>>u>>v;
w=i;
edge[cnt++]={u,v,w};
add(u,v,w);
}
else if(op==2){
int x;
cin>>x;
red[x]=i;
Red.push_back(x);
}
else if(op==3){
int x;
cin>>x;
black[x]=i;
}
else
{
q.push_back(i);
}
}
for(auto x:Red)
if(!vis[x])
dfs(x);
rebuild();
for(auto x:Red)
dfss(x,red[x],1ll*x,2);
for(int i=1;i<=n;i++) ans[i]^=ans[i-1];
for(int i=0;i<q.size();i++){
// cout<<q[i]<<"qwq"<<endl;
int res=ans[q[i]];
if(i)
res^=ans[q[i-1]];
cout<<res<<endl;
}
return 0;
}
/**
* In every life we have some trouble
* When you worry you make it double
* Don't worry,be happy.
**/
以上是关于icpc网络赛 J Red-Black Paths离线,前缀异或,重构图,暴力剪枝的主要内容,如果未能解决你的问题,请参考以下文章
icpc网络赛 J Red-Black Paths离线,前缀异或,重构图,暴力剪枝