迪杰斯特拉:
对n个数的每一位分别用差分约束建图,用sum[i]表示前i项的前缀和,
则可以得出几组关系。建图后跑出的d[i]就是sum的一组可行解。
剪枝:如果op=2;则L,R之间的数有的位数就要求都是1。因此可以
建立sum[i]-sum[0]的边来剪枝。
代码:
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1e5+10;
int op[maxn],L[maxn],R[maxn],x[maxn],n,m;
int sum[maxn],tol,head[maxn],d[maxn],ans[maxn];
bool vis[maxn];
stack<int>P;
struct node
{
int to,cost,next;
}rode[10*maxn];
void init()
{
tol=0;
memset(sum,0,sizeof(sum));
memset(head,-1,sizeof(head));
}
void add(int a,int b,int c)
{
rode[tol].to=b;
rode[tol].cost=c;
rode[tol].next=head[a];
head[a]=tol++;
}
void spfa()
{
for(int i=0;i<=maxn;i++)
d[i]=-INF;
memset(vis,0,sizeof(vis));
P.push(0);vis[0]=1;d[0]=0;
while(!P.empty())
{
int v=P.top();P.pop();vis[v]=0;
for(int i=head[v];i!=-1;i=rode[i].next)
{
node e=rode[i];
if(d[e.to]<d[v]+e.cost)
{
d[e.to]=d[v]+e.cost;
if(!vis[e.to])
{
P.push(e.to);
vis[e.to]=1;
}
}
}
}
}
int main()
{
memset(ans,0,sizeof(ans));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d%d",&op[i],&L[i],&R[i],&x[i]);
for(int t=0;t<20;t++)
{
init();
for(int i=1;i<=n;i++)
{
//0<=sum[i]-sum[i-1]<=1;
//sum[i]-sum[i-1]>=0;
add(i-1,i,0);
//sum[i-1]-sum[i]>=-1;
add(i,i-1,-1);
}
for(int i=1;i<=m;i++)
{
int a=L[i],b=R[i];
if(op[i]==1)
{
if(x[i]&(1<<t))
{
//sum[b]-sum[a-1]>=1;
add(a-1,b,1);
}
else
{
//0<=sum[b]-sum[a-1]<=0;
add(a-1,b,0);
add(b,a-1,0);
}
}
else
{
if(x[i]&(1<<t))
{
//b-a+1<=sum[b]-sum[a-1]<=b-a+1;
//sum[b]-sum[a-1]>=b-a+1;
//sum[a-1]-sum[b]>=a-b-1;
add(a-1,b,b-a+1);
add(b,a-1,a-b-1);
sum[a]++;sum[b+1]--;
}
else
{
//0<=sum[b]-sum[a-1]<=b-a;
//sum[b]-sum[a-1]>=0;
//sum[a-1]-sum[b]>=a-b;
add(a-1,b,0);
add(b,a-1,a-b);
}
}
}
for(int i=1;i<=n;i++)
sum[i]+=sum[i-1];
for(int i=1;i<=n;i++)
if(sum[i])sum[i]=1;
for(int i=1;i<=n;i++)
sum[i]+=sum[i-1];
for(int i=1;i<=n;i++)
{
//sum[i]-sum[0]
add(0,i,sum[i]);
}
spfa();
//for(int i=1;i<=n;i++)
//d[i]=-d[i];
for(int i=1;i<=n;i++)
{
ans[i]=ans[i]+(d[i]-d[i-1])*(1<<t);
}
}
for(int i=1;i<=n;i++)
printf("%d%c",ans[i],i==n?'\n':' ');
return 0;
}
spfa:
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=1e5+10;
int op[maxn],L[maxn],R[maxn],x[maxn],n,m;
int sum[maxn],d[maxn],ans[maxn];
bool vis[maxn];
struct node
{
int to,cost;
};
vector<node>rode[maxn];
void add(int a,int b,int c)
{
node r;r.to=b;r.cost=c;
rode[a].push_back(r);
}
struct node2
{
int id,len;
};
bool operator<(node2 a,node2 b)
{
return a.len<b.len;
}
priority_queue<node2>P;
void Dij()
{
for(int i=0;i<maxn;i++)
d[i]=-INF;
//memset(vis,0,sizeof(vis));
node2 r;r.id=0;r.len=0;
P.push(r);d[0]=0;
while(!P.empty())
{
int v=P.top().id;
int Len=P.top().len;
P.pop();
//vis[v]=1;
if(d[v]>Len)continue;
int L=rode[v].size();
for(int i=0;i<L;i++)
{
node e=rode[v][i];
if(d[e.to]<d[v]+e.cost)
{
d[e.to]=d[v]+e.cost;
r.id=e.to;r.len=d[e.to];
P.push(r);
}
}
}
}
void init()
{
memset(sum,0,sizeof(sum));
for(int i=0;i<maxn;i++)
rode[i].clear();
}
int main()
{
memset(ans,0,sizeof(ans));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d%d",&op[i],&L[i],&R[i],&x[i]);
for(int t=0;t<20;t++)
{
init();
for(int i=1;i<=n;i++)
{
//0<=sum[i]-sum[i-1]<=1;
//sum[i]-sum[i-1]>=0;
add(i-1,i,0);
//sum[i-1]-sum[i]>=-1;
add(i,i-1,-1);
}
for(int i=1;i<=m;i++)
{
int a=L[i],b=R[i];
if(op[i]==1)
{
if(x[i]&(1<<t))
{
//sum[b]-sum[a-1]>=1;
add(a-1,b,1);
}
else
{
//0<=sum[b]-sum[a-1]<=0;
add(a-1,b,0);
add(b,a-1,0);
}
}
else
{
if(x[i]&(1<<t))
{
//b-a+1<=sum[b]-sum[a-1]<=b-a+1;
//sum[b]-sum[a-1]>=b-a+1;
//sum[a-1]-sum[b]>=a-b-1;
add(a-1,b,b-a+1);
add(b,a-1,a-b-1);
sum[a]++;sum[b+1]--;
}
else
{
//0<=sum[b]-sum[a-1]<=b-a;
//sum[b]-sum[a-1]>=0;
//sum[a-1]-sum[b]>=a-b;
add(a-1,b,0);
add(b,a-1,a-b);
}
}
}
for(int i=1;i<=n;i++)
sum[i]+=sum[i-1];
for(int i=1;i<=n;i++)
if(sum[i])sum[i]=1;
for(int i=1;i<=n;i++)
sum[i]+=sum[i-1];
for(int i=1;i<=n;i++)
{
//sum[i]-sum[0]
add(0,i,sum[i]);
}
Dij();
//for(int i=1;i<=n;i++)
//d[i]=-d[i];
for(int i=1;i<=n;i++)
{
ans[i]=ans[i]+(d[i]-d[i-1])*(1<<t);
}
}
for(int i=1;i<=n;i++)
printf("%d%c",ans[i],i==n?'\n':' ');
return 0;
}