洛谷 P2898 [USACO08JAN]haybale猜測Haybale Guessing 解題報告
[USACO08JAN]haybale猜測Haybale Guessing
題目描述
給一段長度為\(n\),每個位置上的數都不同的序列\(a[1\dots n]\)和\(q\)和問答,每個問答是\((x, y, r)\)代表\(\min_\limits{i=a}^ba_i= r\), 要你給出最早的有矛盾的那個問答的編號。
輸入輸出格式
輸入格式:
Line 1: Two space-separated integers: \(N\) and \(Q\)
Lines 2..\(Q+1\): Each line contains three space-separated integers that represent a single query and its reply: \(Q_l\)
輸出格式:
Line 1: Print the single integer \(0\) if there are no inconsistencies among the replies (i.e., if there exists a valid realization of the hay stacks that agrees with all Q queries). Otherwise, print the index from 1..Q of the earliest query whose answer is inconsistent with the answers to the queries before it.
牛客居然考原題...不過題目還是很棒的。
考慮什麽情況會產生矛盾。
- 兩段不相交的區間的最小值相同
一個最小值大的區間完全覆蓋了一個最小值小的區間
一個區間被其他幾個區間完全填充時的,最小值比它們都小。
直接處理很難,如果我們可以按順序處理的話,比如按最小值從大到小排序,無疑會方便很多,但是回答本身就是帶順序的,我們不可以直接打亂它們。
怎麽辦呢,二分答案。這無疑是一個很棒的二分答案的思路。正確性很顯然。
考慮判斷前\(i\)個區間是否產生矛盾,我們按最小值從大到小排序,然後一個一個加入。
- 如果當前區間被其他區間完全覆蓋,返回不合法。
- 如果當前區間與其他區間最小值相同
- 如果兩個區間不交,返回不合法
- 如果兩個區間有交,檢查它們的交集是否被別人覆蓋,拿它們的並集去覆蓋別人。
檢查區間覆蓋可以通過線段樹染色求得,只需要區間賦值\(1\)和區間求和就可以了。
Code:
#include <cstdio>
#include <algorithm>
#include <cstring>
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int N=1e5+10;
int n,q,L[N],R[N],v[N];
struct node
{
int l,r,v,cl,cr;
bool friend operator <(node n1,node n2)
{
return n1.v==n2.v?n1.l<n2.l:n1.v>n2.v;
}
node(){}
node(int l,int r,int v)
{
this->l=l,this->r=r,this->v=v,this->cl=l,this->cr=r;
}
}Q[N],Q0[N];
const int M=4e6+10;
int tag[M],sum[M];
#define ls id<<1
#define rs id<<1|1
void pushdown(int id,int L,int R)
{
if(tag[id])
{
int Mid=L+R>>1;
sum[ls]=Mid+1-L,sum[rs]=R-Mid;
tag[id]=0;tag[ls]=tag[rs]=1;
}
}
int query(int id,int L,int R,int l,int r)
{
if(L==l&&R==r) return sum[id];
pushdown(id,L,R);
int Mid=L+R>>1;
if(r<=Mid) return query(ls,L,Mid,l,r);
else if(l>Mid) return query(rs,Mid+1,R,l,r);
else return query(ls,L,Mid,l,Mid)+query(rs,Mid+1,R,Mid+1,r);
}
void change(int id,int L,int R,int l,int r)
{
if(tag[id]) return;
if(L==l&&R==r)
{
sum[id]=R+1-L,tag[id]=1;
return;
}
int Mid=L+R>>1;
if(r<=Mid) change(ls,L,Mid,l,r);
else if(l>Mid) change(rs,Mid+1,R,l,r);
else change(ls,L,Mid,l,Mid),change(rs,Mid+1,R,Mid+1,r);
sum[id]=sum[ls]+sum[rs];
}
int max(int x,int y){return x>y?x:y;}
int min(int x,int y){return x<y?x:y;}
bool check(int m)
{
rep(i,1,m) Q[i]=node(L[i],R[i],v[i]);
std::sort(Q+1,Q+1+m);
int m_=0;
rep(i,1,m)
{
if(Q[i].v==Q0[m_].v)
{
if(Q0[m_].r<Q[i].l) return false;
else
{
Q0[m_].l=Q[i].l;
Q0[m_].cr=max(Q0[m_].cr,Q[i].r);
Q0[m_].r=min(Q0[m_].r,Q[i].r);
}
}
else Q0[++m_]=Q[i];
}
memset(tag,0,sizeof(tag));
memset(sum,0,sizeof(sum));
rep(i,1,m_)
{
int l=Q0[i].l,r=Q0[i].r,cl=Q0[i].l,cr=Q0[i].cr;
if(query(1,1,n,l,r)==r+1-l) return false;
change(1,1,n,cl,cr);
}
return true;
}
int main()
{
scanf("%d%d",&n,&q);
rep(i,1,q) scanf("%d%d%d",L+i,R+i,v+i);
int l=1,r=q;
if(check(q)) return puts("0"),0;
while(l<r)
{
int mid=l+r>>1;
if(check(mid)) l=mid+1;
else r=mid;
}
printf("%d\n",l);
return 0;
}
2018.10.29
洛谷 P2898 [USACO08JAN]haybale猜測Haybale Guessing 解題報告