挺好的一个题,线段树建图+拆点+最短路。
这个题一眼看上去感觉不就是对于每个条件,对于区间[l,r]的所有点都连上一条边,完了在跑个最短路就完事儿了。
但是看见数据范围的时候就傻眼了,因为最坏情况每一次会有O(n)个点相关,因此,边的数目都会最坏达到O(N*N)无法接受。
那么,对于1e5左右的数据范围,其实很容易联想到O(NlogN)的做法,既然N*N会超时,不如试试能不能有NlogN的做法?
如果能想到线段树就好做了!线段树是对于区间的修改查询的利器,可以把上述的操作转换为,每一次对于一个区间和一个点连边,那么对于一个区间,线段树是可以做到logN的时间复杂度的,所以最多有N*logN条边,N1e5,NlogN不超过2e6 这个范围是可以接受的。
还有一个要点是联想到网络流的拆点技巧,对于每一个点(包括线段树的结点),拆成入点出点,连边。
最后就是求个最短路了,我用的是spfa,不知道dijkstra能不能过(应该也可以,但是我没试)。
CODE:
//#pragma GCC optimize(2) #include<bits/stdc++.h> using namespace std; #define fi first #define se second #define all(x) (x).begin(),(x).end() #define mp make_pair #define pb push_back #define input_fast std::ios::sync_with_stdio(false);std::cin.tie(0) #define local freopen("in.text","r",stdin) #define pi acos(-1) const int mo=1e9+7; typedef long long ll; typedef pair<int,int> pii; typedef vector<int> vi; ll qp(ll a,ll b){if(a==0) return 0;ll res=1;a%=mo;for(;b;b>>=1){if(b&1)res=res*a%mo;a=a*a%mo;}return res;} template<class T> bool read(T & ret)//ll,int,double,float,+/- { char c;int sgn;T bit=0.1;if(c=getchar(),c==EOF) return 0;while(c!='-' && c!='.' && (c<'0' || c>'9')) c=getchar();sgn=(c=='-')?-1:1;ret=(c=='-')?0:(c-'0');while(c=getchar(),c>='0' && c<='9') ret=ret*10+(c-'0');if(c==' '||c=='\n') {ret*=sgn;return 1;}while(c=getchar(),c>='0' && c<='9') ret+=(c-'0')*bit,bit/=10;ret*=sgn;return 1; } int n,q,s; const int N=100010,M=N*20; int idx; int h[M],e[M],f[M],ne[M],w[M]; ll d[M]; int id; struct Node{ int l,r,idx; }tr[2][N<<2]; map<int,int> mmp[2]; void add(int a,int b,int c) { e[id] = b,w[id]=c,ne[id]=h[a],h[a]=id++; } void add_(int now,int a,int b,int c) { a=tr[now][a].idx; b=tr[now][b].idx; e[id] = b,w[id]=c,ne[id]=h[a],h[a]=id++; } void build(int now,int u,int l,int r) { tr[now][u] = {l,r,++idx}; if(l==r) { mmp[now][l]=idx; return ; } int mid=l+r>>1; build(now,u<<1,l,mid); build(now,u<<1|1,mid+1,r); if(now==0)add_(0,u,u<<1,0),add_(0,u,u<<1|1,0);//ru else add_(1,u<<1|1,u,0),add_(1,u<<1,u,0);//chu } void add1(int v,int u,int l,int r,int w) { if(tr[0][u].l>=l&&tr[0][u].r<=r) {add(mmp[1][v],tr[0][u].idx,w);return ;} int mid=tr[0][u].l+tr[0][u].r>>1; if(l<=mid) add1(v,u<<1,l,r,w); if(r>mid) add1(v,u<<1|1,l,r,w); } void add2(int v,int u,int l,int r,int w) { if(tr[1][u].l>=l&&tr[1][u].r<=r) {add(tr[1][u].idx,mmp[0][v],w);return ;} int mid=tr[1][u].l+tr[1][u].r>>1; if(l<=mid) add2(v,u<<1,l,r,w); if(r>mid) add2(v,u<<1|1,l,r,w); } bool st[M]; void spfa() { queue<int> q; s=mmp[1][s]; q.push(s); memset(d,0x3f,sizeof d); d[s]=0; while(q.size()) { int t=q.front(); // cout<<"spfa"<<t<<endl; q.pop(); st[t]=false; for(int i=h[t];~i;i=ne[i]) { int ver=e[i]; if(d[ver]>d[t]+w[i]) { d[ver]=d[t]+w[i]; if(!st[ver]) { st[ver]=true; q.push(ver); } } } } } void gao() { for(int i=1;i<=n;++i) { add(mmp[0][i],mmp[1][i],0); } } signed main(){ memset(h,-1,sizeof h); cin>>n>>q>>s; build(0,1,1,n); build(1,1,1,n); while(q--) { int op; cin>>op; int l,r,v,u,w; if(op==1) { cin>>u>>v>>w; add(mmp[1][u],mmp[0][v],w); } else if(op==2) { cin>>v>>l>>r>>w; add1(v,1,l,r,w); } else { cin>>v>>l>>r>>w; add2(v,1,l,r,w); } } gao(); spfa(); for(int i=1;i<=n;++i) if(d[mmp[1][i]]>1e18) cout<<"-1 ";else cout<<d[mmp[1][i]]<<' '; return 0; }