noip模拟23
A. 联
一个典型的线段树,
发现\(1\)和\(2\)操作都是比较好实现的,
\(3\)操作直接修改懒标记即可.
A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
#define p() printf("Pass")
#define ll long long int
#define re register ll
#define lf double
#define lb lower_bound
#define ub upper_bound
#define mp make_pair
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define fill(x,y) memset(x,y,sizeof x);
#define copy(x,y) memcpy(x,y,sizeof x);
#define pass() printf("Pass")
inline void read(ll &ss)
{
ss=0; bool cit=0; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=1;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
if(cit) ss=-ss;
}
inline void write(ll ss)
{
static int stas[35]; int topps=0;
if(ss<0) putchar('-'),ss=-ss;
do{stas[++topps]=ss%10,ss/=10;}while(ss);
while(topps) putchar(stas[topps--]+48); puts("");
}
} using namespace BSS;
const ll N=1e5+50;
ll m,n;
ll le[N],ri[N],opt[N];
ll lsh[N*8];
struct I { ll l,r,l0,l1,lazy; } tr[N*64];
inline void pushup(ll x)
{
if(tr[x<<1].l0==-1) tr[x].l0=tr[x<<1|1].l0;
else tr[x].l0=tr[x<<1].l0;
if(tr[x<<1].l1==-1) tr[x].l1=tr[x<<1|1].l1;
else tr[x].l1=tr[x<<1].l1;
return ;
}
inline void fz1(ll x)
{
tr[x].l1=tr[x].l; tr[x].l0=-1;
}
inline void fz2(ll x)
{
tr[x].l0=tr[x].l; tr[x].l1=-1;
}
inline void fz3(ll x)
{
ll temp=tr[x].l0; tr[x].l0=tr[x].l1; tr[x].l1=temp;
}
inline void ch3(ll x)
{
if(tr[x].lazy==1) tr[x].lazy=2;
else if(tr[x].lazy==2) tr[x].lazy=1;
else if(tr[x].lazy==0) tr[x].lazy=3;
else tr[x].lazy=0;
}
inline void spread(ll x)
{
if(tr[x].lazy)
{
if(tr[x].lazy==1)
{
fz1(x<<1); fz1(x<<1|1);
tr[x<<1].lazy=tr[x].lazy;
tr[x<<1|1].lazy=tr[x].lazy;
}
if(tr[x].lazy==2)
{
fz2(x<<1); fz2(x<<1|1);
tr[x<<1].lazy=tr[x].lazy;
tr[x<<1|1].lazy=tr[x].lazy;
}
if(tr[x].lazy==3)
{
fz3(x<<1); fz3(x<<1|1);
ch3(x<<1); ch3(x<<1|1);
}
tr[x].lazy=0;
}
return ;
}
void build(ll x,ll l,ll r)
{
tr[x].l=l; tr[x].r=r;
tr[x].l0=l; tr[x].l1=-1;
if(l==r)
{
tr[x].l0=l; tr[x].l1=-1;
return ;
}
ll mid=(l+r)>>1;
build(x<<1,l,mid); build(x<<1|1,mid+1,r);
pushup(x);
return ;
}
void change(ll x,ll ql,ll qr,ll sp)
{
if(tr[x].l>=ql and tr[x].r<=qr)
{
if(sp==1) fz1(x);
if(sp==2) fz2(x);
if(sp==3) fz3(x);
if(sp==3) ch3(x);
else tr[x].lazy=sp;
return ;
}
spread(x);
ll mid=(tr[x].l+tr[x].r)>>1;
if(ql<=mid) change(x<<1,ql,qr,sp);
if(qr>=mid+1) change(x<<1|1,ql,qr,sp);
pushup(x);
return ;
}
signed main()
{
read(m); ll cnt=0;
lsh[++cnt]=1;
for(re i=1;i<=m;i++)
{
read(opt[i]);
read(le[i]); read(ri[i]);
lsh[++cnt]=le[i]; lsh[++cnt]=le[i]+1;
lsh[++cnt]=ri[i]; lsh[++cnt]=ri[i]+1;
n=max(ri[i],n);
}
sort(lsh+1,lsh+cnt+1);
cnt=unique(lsh+1,lsh+cnt+1)-lsh-1;
ll temp=lb(lsh+1,lsh+1+cnt,1)-lsh,tmp1,tmp2;
for(ll i=1;i<=m;i++)
{
temp=le[i]; tmp1=le[i]+1;
le[i]=lb(lsh+1,lsh+1+cnt,temp)-lsh;
temp=ri[i]; tmp1=ri[i]+1;
ri[i]=lb(lsh+1,lsh+1+cnt,temp)-lsh;
// cout<<opt[i]<<" "<<le[i]<<" "<<ri[i]<<endl;
}
build(1,1,cnt);
for(re i=1;i<=m;i++)
{
change(1,le[i],ri[i],opt[i]);
if(tr[1].l0==-1) write(n+1);
else write(lsh[tr[1].l0]);
}
return 0;
}
B. 赛
贪心是错误思路,考场上糊了一个以为对的优先队列.
正解其实还是排除了一些无用状态后在所有状态中选取最优解,
关于如何维护最优解,发现线段树就可以.
把所有的物品根据两个人是否喜欢分成四类.
如果枚举两个人都喜欢的物品中选了 \(r\) 个,那么在只有第一个人喜欢的物品中和只有第二个人喜欢的物品至少都还要选 \(k−r\) 个,显然在这里会直接选择权值最小的 \(k−r\) 个.
之后若还没有选够 \(m\) 个,那么需要在剩下的物品中随便选使得达到 \(m\) 个.
所以可以从小到大枚举 \(r\),然后用线段树维护一下 “剩下的物品”,支持查询前 \(x\) 小值之和就可以了.
B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
#define p() printf("Pass")
#define ll long long int
#define re register ll
#define lf double
#define lb lower_bound
#define ub upper_bound
#define mp make_pair
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define fill(x,y) memset(x,y,sizeof x);
#define copy(x,y) memcpy(x,y,sizeof x);
#define pass() printf("Pass")
inline void read(ll &ss)
{
ss=0; bool cit=0; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=1;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
if(cit) ss=-ss;
}
inline void write(ll ss)
{
static int stas[35]; int topps=0;
if(ss<0) putchar('-'),ss=-ss;
do{stas[++topps]=ss%10,ss/=10;}while(ss);
while(topps) putchar(stas[topps--]+48);
}
} using namespace BSS;
const ll N=2e5+50;
ll m,n,s,sum1,sum2,cnt,tot,ans;
ll vis[N],vis1[N],vis2[N],t1[N],t2[N],lsh[N];
ll siz[N*64],rt[N*64],ls[N*64],rs[N*64],sum[N*64];
struct II { ll id,pay; } p[N];
bool comp(II i,II j) { return i.pay==j.pay ? i.id<j.id : i.pay<j.pay ; }
vector<II> vec,vec1,vec2;
void update(ll &x,ll l,ll r,ll val,ll num)
{
if(!x) x=++tot;
if(l==r)
{
siz[x]+=num;
sum[x]=siz[x]*lsh[val];
return ;
}
ll mid=(l+r)>>1;
if(val<=mid) update(ls[x],l,mid,val,num);
else update(rs[x],mid+1,r,val,num);
siz[x]=siz[ls[x]]+siz[rs[x]];
sum[x]=sum[ls[x]]+sum[rs[x]];
return ;
}
ll query(ll x,ll l,ll r,ll pos)
{
if(!pos) return 0;
if(!x) return 0;
if(l==r)
{
return sum[x];
}
ll mid=(l+r)>>1;
if(pos<=siz[ls[x]])
{
// cout<<l<<" "<<mid<<" endl"<<endl;
// cout<<endl<<query(ls[x],l,mid,pos)<<" skrkkk\n";
return query(ls[x],l,mid,pos);
}
else return sum[ls[x]]+query(rs[x],mid+1,r,pos-siz[ls[x]]);
}
signed main()
{
read(n); read(m); read(s);
for(re i=1;i<=n;i++)
{
read(p[i].pay);
p[i].id=i;
lsh[++cnt]=p[i].pay;
}
sort(p+1,p+1+n,comp);
sort(lsh+1,lsh+1+cnt);
cnt=unique(lsh+1,lsh+1+cnt)-lsh-1;
read(sum1);
for(re i=1;i<=sum1;i++)
{
read(t1[i]);
vis[t1[i]]++;
}
read(sum2);
for(re i=1;i<=sum2;i++)
{
read(t2[i]);
vis[t2[i]]+=2;
}
for(re i=1;i<=n;i++)
{
p[i].pay=lb(lsh+1,lsh+1+cnt,p[i].pay)-lsh;
update(rt[1],1,cnt+1,p[i].pay,1);
if(vis[p[i].id]==1)
{
vec1.push_back(p[i]);
}
if(vis[p[i].id]==2)
{
vec2.push_back(p[i]);
}
if(vis[p[i].id]==3)
{
vec.push_back(p[i]);
}
}
if(vec.size()+m<2*s)
{
printf("-1");
return 0;
}
fill(vis,0); ll temp,tmp=0; ans=1e15;
ll i=min((ll)vec.size(),s),j=0,k1=0,k2=0;
for(re k=0;k<i;k++)
{
tmp+=lsh[vec[k].pay];
update(rt[1],1,cnt+1,vec[k].pay,-1);
}
while(i>=0 and i+m>=2*s)
{
for(;k1<s-i;k1++)
{
tmp+=lsh[vec1[k1].pay];
// cout<<lsh[vec1[k1].pay]<<" ";
update(rt[1],1,cnt+1,vec1[k1].pay,-1);
}
for(;k2<s-i;k2++)
{
tmp+=lsh[vec2[k2].pay];
update(rt[1],1,cnt+1,vec2[k2].pay,-1);
}
temp=query(rt[1],1,cnt+1,m+i-2*s);
tmp+=temp;
ans=min(ans,tmp);
if(i==0) break;
tmp-=lsh[vec[i-1].pay];
tmp-=temp;
update(rt[1],1,cnt+1,vec[i-1].pay,1);
i--;
}
write(ans);
return 0;
}
C. 题
一个\(dp\),
考场上看到有树的部分分就知道这个题肯定不是仅仅局限于图论了,但还是没做出来.
C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
#define p() printf("Pass")
#define ll long long int
#define re register ll
#define lf double
#define lb lower_bound
#define ub upper_bound
#define mp make_pair
#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
#define Fill(x,y) memset(x,y,sizeof x);
#define Copy(x,y) memcpy(x,y,sizeof x);
inline ll read()
{
ll ss=0; bool cit=0; char ch;
while(!isdigit(ch=getchar())) if(ch=='-') cit=1;
while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
if(cit) ss=-ss; return ss;
}
inline void write(ll ss)
{
static int stas[35]; int topps=0;
if(ss<0) putchar('-'),ss=-ss;
do{stas[++topps]=ss%10,ss/=10;}while(ss);
while(topps) putchar(stas[topps--]+48); puts("");
}
} using namespace BSS;
const ll N=450,M=5e4+50;
ll n,m,sum;
ll u[M],v[M];
ll f[N][N],g[N];
signed main()
{
n=read(); m=read();
for(re i=1;i<=m;i++) u[i]=read(),v[i]=read();
for(re i=1;i<=n;i++) f[i][i]=1,g[i]=1;
for(re i=1;i<=n;i++)
{
for(re j=m;j>=1;j--)
{
if(f[i][u[j]] and f[i][v[j]]) // 如果 i 活的条件是 u[j] 和 v[j]都活下来,那么 i 必死..
{
g[i]=0;
break;
}
if(f[i][u[j]])
{
f[i][v[j]]=1;
continue;
}
if(f[i][v[j]])
{
f[i][u[j]]=1;
continue;
}
if( (!f[i][u[j]]) and (!f[i][v[j]]) )
{
continue;
}
}
}
bool flag;
for(re i=1;i<=n;i++)
{
if(!g[i]) continue;
for(re j=i+1;j<=n;j++)
{
if(!g[j]) continue;
flag=1;
for(re k=1;k<=n;k++)
{
if(f[i][k] and f[j][k])
{
flag=0;
break;
}
}
if(flag) sum++;
}
}
write(sum);
return 0;
}

浙公网安备 33010602011771号