区间连边的图题
线段树优化建图
然而我懒得写线段树
写暴力!暴力!
于是用了书名号魔改线段树优化建图的方法:点和区间连边时,新建一个点,把两个点连上权值为val的边,然后把区间向新点连权值为0的边(还是个暴力
前面的点跑的比暴力快然而从第8个点开始RE 再大就MLE了qwq
老老实实写线段树吧孩子!
暴力CODE:
#include<iostream>
#include<cstdio>
#include<queue>
#define ll long long
#define pii pair<ll, int>
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
int n, q, s;
struct edge{
int go, nxt, val;
}e[6000005];
int head[6000005], vis[6000005];
ll dis[6000005];
priority_queue<pii, vector<pii> ,greater<pii> >qu;
inline int qr(){
int x=0;
char ch=getchar();
for(; isdigit(ch); ch=getchar()) x=x*10+ch-48;
return x;
}
void add(int u, int v, int w){
static int tot;
e[++tot].nxt=head[u];
e[tot].go=v;
e[tot].val=w;
head[u]=tot;
}
void dij(int s){
for(int i=1; i<=n; i++)
dis[i]=INF;
dis[s]=0;
qu.push(make_pair(0, s));
while(!qu.empty()){
int u=qu.top().second;
qu.pop();
if(vis[u])continue;
vis[u]=1;
for(int i=head[u]; i; i=e[i].nxt){
int v=e[i].go;
if(!vis[v]&&dis[u]+e[i].val<dis[v]){
dis[v]=dis[u]+e[i].val;
qu.push(make_pair(dis[v], v));
}
}
}
}
int main(){
n=qr();q=qr();s=qr();
int qwq, a, b, c, d;
for(int i=1; i<=q; i++){
qwq=qr();
if(qwq==1){
a=qr();b=qr();c=qr();
add(a, b, c);
}else if(qwq==2){
a=qr();b=qr();c=qr();d=qr();
for(int i=b; i<=c; i++)
add(a, i, d);
}else{
a=qr();b=qr();c=qr();d=qr();
for(int i=b; i<=c; i++)
add(i, a, d);
}
}
dij(s);
for(int i=1; i<=n; i++)
printf("%lld ", dis[i]==INF?dis[i]=-1:dis[i]);
return 0;
}
正解(两颗线段树CODE:
#include<bits/stdc++.h>
#define lson (i<<1)
#define rson (i<<1|1)
using namespace std;
typedef long long ll;
typedef pair< ll, int > pli;
const ll inf =1e18+5;
const int N =1e5+5;
struct node
{
int l,r;
int num;
}ta[N<<2],tb[N<<2];
int pa[N],pb[N];
struct node1
{
ll w;
int v;
node1(ll _w,int _v):w(_w),v(_v){}
};
vector< node1 >ve[N*8];
int vis[N*8];
ll dis[N*8];
int tot;
void builda(int i,int l,int r)// 自下向上建边
{
ta[i].l=l; ta[i].r=r; ta[i].num=++tot;
if(ta[i].l==ta[i].r){
pa[l]=ta[i].num;
return ;
}
int mid=(ta[i].l+ta[i].r)>>1;
builda(lson,l,mid);
builda(rson,mid+1,r);
ve[ta[lson].num].push_back(node1(0,ta[i].num));
ve[ta[rson].num].push_back(node1(0,ta[i].num));
}
void updatea(int i,int l,int r,int num,ll w)
{
if(ta[i].l==l&&ta[i].r==r){ // cong l,r dao u
ve[ta[i].num].push_back(node1(w,num)); // 从a线段树的区间向b线段树的底部建一条边
return ;
}
int mid=(ta[i].l+ta[i].r)>>1;
if(r<=mid) updatea(lson,l,r,num,w);
else if(l>mid) updatea(rson,l,r,num,w);
else{
updatea(lson,l,mid,num,w);
updatea(rson,mid+1,r,num,w);
}
}
void buildb(int i,int l,int r) // 自上向下建边
{
tb[i].l=l; tb[i].r=r; tb[i].num=++tot;
if(tb[i].l==tb[i].r){
pb[l]=tb[i].num;
ve[tb[i].num].push_back(node1(0,pa[l])); //从b线段树的底部向a线段树的底部建一条0遍表示两个点在逻辑上是一个点
//cout<<"**** u "<<tb[i].num<<" "<<pa[l]<<endl;
return ;
}
int mid=(tb[i].l+tb[i].r)>>1;
buildb(lson,l,mid);
buildb(rson,mid+1,r);
ve[tb[i].num].push_back(node1(0,tb[lson].num));
ve[tb[i].num].push_back(node1(0,tb[rson].num));
}
void updateb(int i,int l,int r,int num,ll w)
{
if(tb[i].l==l&&tb[i].r==r){
ve[num].push_back(node1(w,tb[i].num)); // 从a线段树的底部向b线段树的 区间建一条边
//cout<<"****u "<<num<<" "<<tb[i].num<<endl;
return ;
}
int mid=(tb[i].l+tb[i].r)>>1;
if(r<=mid) updateb(lson,l,r,num,w);
else if(l>mid) updateb(rson,l,r,num,w);
else{
updateb(lson,l,mid,num,w);
updateb(rson,mid+1,r,num,w);
}
}
int n,m,q,s;
void dij(int st)
{
memset(vis,0,sizeof(vis));
for(int i=0;i<=8*n;i++) dis[i]=inf;
dis[st]=0;
pli tmp;
priority_queue< pli,vector<pli> ,greater<pli> >q;
q.push(pli(0,st));
int u,v;
while(!q.empty()){
tmp=q.top(); q.pop();
u=tmp.second;
if(tmp.first>dis[u]) continue;
vis[u]=1;
//cout<<"****** u "<<u<<" "<<dis[u]<<endl;
for(int i=0;i<ve[u].size();i++)
{
v=ve[u][i].v;
if(vis[v]) continue;
if(dis[v]>dis[u]+ve[u][i].w){
dis[v]=dis[u]+ve[u][i].w;
//cout<<"*** v "<<v<<" "<<dis[v]<<" "<<ve[u][i].w<<endl;
q.push(pli(dis[v],v));
}
}
}
for(int i=1;i<=n;i++){
if(dis[pa[i]]!=inf){
printf("%lld ",dis[pa[i] ]);
}
else printf("-1 ");
}
return ;
}
int main()
{
int op,l,r,u,v;
ll w;
scanf("%d %d %d",&n,&m,&s);
int rta=1;
builda(1,1,n);
int rtb=1;
//cout<<"rtb "<<rtb<<endl;
buildb(rtb,1,n);
while(m--)
{
scanf("%d",&op);
if(op==1){
scanf("%d %d %lld",&u,&v,&w);
ve[pa[u]].push_back(node1(w,pb[v]));
}
else if(op==2){ // 从 u 到 l,r
scanf("%d %d %d %lld",&u,&l,&r,&w);
updateb(rtb,l,r,pa[u],w);
}
else if(op==3){ // 从 l,r到u
scanf("%d %d %d %lld",&u,&l,&r,&w);
updatea(rta,l,r,pb[u],w);
}
}
dij(pa[s]);
return 0;
}