P1533 可憐的狗狗
裸的主席樹,但是我想到一種其它的做法。
用莫隊加上平衡樹,原因為題目保證 \(a_i\) 互不相同,算了一下複雜度勉強能過。
平衡樹的話可以使用 pbds 內建的那顆。
跑得飛快,碾壓主席樹。
點選檢視程式碼
#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define int long long
using namespace std;
using namespace __gnu_pbds;
tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> tr;//從小到大
int findnum(int k){auto it=tr.find_by_order(k-1);return ((it!=tr.end())?(*it):1e9+7);}//查元素
// int findrank(int x){return tr.order_of_key(x)+1;}//查排名
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int mod=1e9+7;
const int maxn=1e6+10;
const int inf=1e17;
const double eps=1e-10;
int n,m;
int a[maxn];
int id[maxn],len;
struct no
{
int l,r,k,pos;
inline friend bool operator < (no q,no w)
{
if(id[q.l]==id[w.l])
{
if(id[q.l]&1) return q.r<w.r;
else return q.r>w.r;
}
else
{
return q.l<w.l;
}
}
}q[maxn];
int ans[maxn];
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
cin>>n>>m;
for(int i=1;i<=n;i++)
{
a[i]=read();
}
for(int i=1;i<=m;i++)
{
q[i]={read(),read(),read(),i};
}
len=sqrt(n*1.0);
for(int i=1;i<=n;i++)id[i]=(i-1)/len+1;
sort(q+1,q+m+1);
int l=0,r=0;
for(int i=1;i<=m;i++)
{
while(r<q[i].r)
{
r++;
tr.insert(a[r]);
}
while(r>q[i].r)
{
tr.erase(a[r]);
r--;
}
while(l<q[i].l)
{
tr.erase(a[l]);
l++;
}
while(l>q[i].l)
{
l--;
tr.insert(a[l]);
}
int res=findnum(q[i].k);
ans[q[i].pos]=res;
}
for(int i=1;i<=m;i++)
printf("%lld\n",ans[i]);
return 0;
}
P1668 [USACO04DEC] Cleaning Shifts S
典型線段樹最佳化DP,設 \(dp_i\) 表示區間 \([1,i]\) 所需最小線段數量。初始化所有 \(l=1\) 的線段都有 \(dp_r=1\)。
然後按照 \(r\) 排序,對於當前的 \(r\),轉移的時候顯然 \(dp_r=dp_j+1~~ (l-1\le j \le r)\)。
然後一個線段樹搞一下就結束了。
點選檢視程式碼
#include<bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
#define int long long
using namespace std;
// using namespace __gnu_pbds;
// tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> tr;//從小到大
// int findnum(int k){auto it=tr.find_by_order(k-1);return ((it!=tr.end())?(*it):1e9+7);}//查元素
// int findrank(int x){return tr.order_of_key(x)+1;}//查排名
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int mod=1e9+7;
const int maxn=1e6+10;
const int inf=1e17;
const double eps=1e-10;
int n,T;
struct no
{
int l,r;
inline friend bool operator < (no x,no y)
{
return x.r<y.r||x.r==y.r&&x.l<y.l;
}
}a[maxn];
struct Seg
{
int l,r,d;
}t[maxn<<2];
void build(int p,int l,int r)
{
t[p].l=l,t[p].r=r;
if(l==r)
{
t[p].d=1e9+7;
return ;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
t[p].d=min(t[p*2].d,t[p*2+1].d);
}
void upd(int p)
{
t[p].d=min(t[p*2].d,t[p*2+1].d);
}
void change(int p,int x,int k)
{
if(t[p].l==t[p].r)
{
t[p].d=min(t[p].d,k);
return ;
}
int mid=(t[p].l+t[p].r)>>1;
if(x<=mid)change(p<<1,x,k);
else change(p<<1|1,x,k);
upd(p);
}
int ask(int p,int l,int r)
{
if(t[p].l>=l&&t[p].r<=r)
{
return t[p].d;
}
int mid=(t[p].l+t[p].r)/2,re=1e9+7;
if(mid>=l)re=min(re,ask(p*2,l,r));
if(mid<r)re=min(re,ask(p*2+1,l,r));
return re;
}
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
cin>>n>>T;
for(int i=1;i<=n;i++)
{
a[i].l=read(),a[i].r=read();
}
build(1,1,T);
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)if(a[i].l==1)change(1,a[i].r,1);
for(int i=1;i<=n;i++)
{
int mii=ask(1,a[i].r,a[i].r);
mii=min(mii,ask(1,a[i].l-1,a[i].r-1)+1);
change(1,a[i].r,mii);
}
int ans=ask(1,T,T);
cout<<(ans>1e9?-1:ans);
return 0;
}
P6348 [PA2011] Journeys
線段樹最佳化建圖板子。
需要注意的是,一不小心就會RE,所以稍微改一下建圖方式每次開一個虛擬點進行連邊即可。
空間快爆掉。
點選檢視程式碼
#include<bits/stdc++.h>
// #include <ext/pb_ds/assoc_container.hpp>
// #include <ext/pb_ds/tree_policy.hpp>
#define int long long
using namespace std;
// using namespace __gnu_pbds;
// tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> tr;//從小到大
// int findnum(int k){auto it=tr.find_by_order(k-1);return ((it!=tr.end())?(*it):1e9+7);}//查元素
// int findrank(int x){return tr.order_of_key(x)+1;}//查排名
inline int read()
{
int w=1,s=0;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
while(isdigit(ch)){s=s*10+(ch-'0');ch=getchar();}
return w*s;
}
const int mod=1e9+7;
const int maxn=1e6+10;
const int inf=1e17;
const double eps=1e-10;
int n,m,s,k;
struct Seg
{
int l,r;
}t[5000100];
struct no
{
int y,v;
};
vector<no> G[maxn];
void add(int x,int y,int v)
{
G[x].push_back({y,v});
}
int id[maxn];
void build(int p,int l,int r)
{
t[p].l=l,t[p].r=r;
if(l==r)
{
id[l]=p;
return ;
}
int mid=(l+r)>>1;
add(p,p*2,0);add(p,p*2+1,0);
add(p*2+k,p+k,0);add(p*2+1+k,p+k,0);
build(p*2,l,mid);
build(p*2+1,mid+1,r);
}
vector<int> vv;
void change(int p,int l1,int r1)
{
if(t[p].l>=l1&&t[p].r<=r1)
{
vv.push_back(p);
return ;
}
int mid=(t[p].l+t[p].r)>>1;
if(l1<=mid)change(p*2,l1,r1);
if(mid<r1)change(p*2+1,l1,r1);
}
void change2(int p,int l1,int r1)
{
if(t[p].l>=l1&&t[p].r<=r1)
{
for(auto i : vv)
{
add(i+k,p,1);
add(p+k,i,1);
}
return ;
}
int mid=(t[p].l+t[p].r)>>1;
if(l1<=mid)change2(p*2,l1,r1);
if(mid<r1)change2(p*2+1,l1,r1);
}
struct dii
{
int y,id;
inline friend bool operator < (dii x,dii y)
{
return x.y>y.y;
}
};
int dis[maxn];
bool vis[maxn];
void distla(int s)
{
memset(dis,0x3f,sizeof dis);
priority_queue<dii> q;
dis[s]=0;
q.push({0,s});
while(!q.empty())
{
int u=q.top().id;
q.pop();
if(vis[u])continue;
vis[u]=1;
for(auto i : G[u])
{
int y=i.y,v=i.v;
if(dis[u]+v<dis[y])
{
dis[y]=dis[u]+v;
if(!vis[y])
q.push({dis[y],y});
}
}
}
}
signed main()
{
#ifdef Lydic
freopen(".in","r",stdin);
freopen(".out","w",stdout);
#endif
cin>>n>>m>>s;
k=5e5+1;
build(1,1,n);
for(int i=1;i<=n;i++)
{
add(id[i],id[i]+k,0);
add(id[i]+k,id[i],0);
}
for(int i=1;i<=m;i++)
{
int l1=read(),r1=read(),l2=read(),r2=read();
vv.clear();
change(1,l1,r1);
change2(1,l2,r2);
}
distla(id[s]+k);
for(int i=1;i<=n;i++)
cout<<(dis[id[i]]==0x3f3f3f3f3f3f3f3fll?-1:dis[id[i]])<<endl;
return 0;
}