Codeforces 671E Organizing a Race(욕심, 세그먼트 트리)
https://codeforces.com/contest/671/problem/E
문제풀이
전혀 할 줄 몰라요...기본적으로lk의 코드ruogu를 베낀 문제풀이입니다.https://www.luogu.com.cn/blog/ruogu-pupil/cf671esoj809-tan-xin-er-fen-tan-suo-shen-xian#Orz lk & ruogu 주: 본문에서\(a, b, m\)는 각각 원제에서\(g, w, k\)를 어떻게 분배할 것인지를 먼저 고려한다는 것을 나타낸다. 분명한 욕심은 왼쪽에서 오른쪽으로 힘을 내야 할 때 더해서 왼쪽에서 오른쪽으로 합법적임을 보증하고 마지막에 남은 돈을 모두 오른쪽 단점으로 더해서 가능한 한 오른쪽에서 왼쪽으로 합법적임을 보증하는 것이다.(f i=f i=f {i-1}+a {i-1}-b {ii i=f i=f b {i-1}-b {i-1}, g i i=g i=g i=g i i i i i ii i i i i b i b\),\(j\gt i\),\(g j\) 는\(1\) 를 줄이고 변경된\(g\) 를\(h\) 수조로 설정하면 뒤에서\(l\) 를 열거합니다.단조로운 창고를 유지하는 김에\(l\)에서 오른쪽으로 갈 수 있는 최대\(r\)는 단조로운 창고에서 직접 2분의 1로 구할 수 있음을 고려하여\(R\)로 기록합니다.우리는 단조로운 창고를 유지하는 동시에 세그먼트 트리 구간에\(h\)를 추가하면\(r\)에\(h r=g r+m\)가 있습니다.\(g r-m\le min^{r-1} {i=l}h i\)를 충족시키고\(l\le i\le R\)의 최대\(r\)를 조회하려면 접두사와 접두사를 사용하는 것이 묘하다.\(r\)가 다른 값을 얻었을 때\(g r\)의 증가량이 항상\(m\)로 늘어나는 것을 보장한다. 직접 라인 트리의 2분을 고려하고 라인 트리의 노드에 도착했을 때만약\(R>mid\) 왼쪽 반쪽의\(h\)의 최소값이 오른쪽\(g\)의 최소값\(-k\)보다 크면 오른쪽으로 돌아가고 오른쪽에 반드시 답이 있을 것이다(단,\(R\)의 왼쪽에 있을 수는 없다).이는 왼쪽 끝에 있는\(h i\geg i-k\), 오른쪽 끝에 있는\(h i\le g i-k\le g r-k\)가 모두 충족되기 때문입니다.발견된 점이\(R\)의 오른쪽에 있는 경우 해결되지 않은 상태로 돌아가면 복잡성에 영향을 주지 않고 한 번만 발생합니다.오른쪽에 풀이 없거나\(R\le mid\)가 반환되면 현재 최소\(h\)가 왼쪽\(g\)의 최소값\(-m\)보다 크면 왼쪽으로 반환되고 그렇지 않으면 풀이 없음으로 돌아갑니다.한 번에 왼쪽으로 돌아가는 것은 해를 찾을 수 있기 때문에 복잡도가 정확하다.(자세히 설명하지 못할 수도 있습니다...코드 참조) 시간 복잡도\(O(n\log n)\).
코드
#include
#define llong long long
#define mkpr make_pair
#define riterator reverse_iterator
using namespace std;
inline int read()
{
int x=0,f=1; char ch=getchar();
for(;!isdigit(ch);ch=getchar()) {if(ch=='-') f = -1;}
for(; isdigit(ch);ch=getchar()) {x = x*10+ch-'0';}
return x*f;
}
const int N = 1e6;
const llong INF = 1e16;
llong a[N+3],b[N+3],f[N+3],g[N+3];
int stk[N+3];
int n,tp; llong m; int ans;
struct SgTNode
{
llong h,g,tag;
SgTNode() {h = INF,g = -INF;}
} sgt[(N<<2)+3];
void pushdown(int u)
{
if(!sgt[u].tag) return; llong tag = sgt[u].tag;
sgt[u<<1].h += tag,sgt[u<<1].tag += tag;
sgt[u<<1|1].h += tag,sgt[u<<1|1].tag += tag;
sgt[u].tag = 0ll;
}
void updateg(int u,int le,int ri,int pos)
{
if(le==ri) {sgt[u].g = sgt[u].h = g[pos]; return;}
int mid = (le+ri)>>1; pushdown(u);
if(pos<=mid) {updateg(u<<1,le,mid,pos);}
else {updateg(u<<1|1,mid+1,ri,pos);}
sgt[u].g = min(sgt[u<<1].g,sgt[u<<1|1].g); sgt[u].h = min(sgt[u<<1].h,sgt[u<<1|1].h);
}
void addh(int u,int le,int ri,int lb,int rb,llong x)
{
if(le>=lb && ri<=rb) {sgt[u].h += x,sgt[u].tag += x; return;}
int mid = (le+ri)>>1; pushdown(u);
if(lb<=mid) {addh(u<<1,le,mid,lb,rb,x);}
if(rb>mid) {addh(u<<1|1,mid+1,ri,lb,rb,x);}
sgt[u].h = min(sgt[u<<1].h,sgt[u<<1|1].h);
}
int query(int u,int le,int ri,int rb,llong x)
{
if(le>rb) {return -1;}
if(le==ri) {return le;}
int mid = (le+ri)>>1; pushdown(u);
llong lv = min(x,sgt[u<<1].h);
if(rb>mid && lv>=sgt[u<<1|1].g-m)
{
int ret = query(u<<1|1,mid+1,ri,rb,lv);
if(ret!=-1) return ret;
}
if(sgt[u<<1].g-m<=x) return query(u<<1,le,mid,rb,x);
return -1;
}
int main()
{
scanf("%d%I64d",&n,&m);
for(int i=1; i=1; i--)
{
updateg(1,1,n,i);
while(tp>0 && f[stk[tp]]>=f[i])
{
if(tp>1)
{
addh(1,1,n,stk[tp-1]-1,n,f[stk[tp]]-f[stk[tp-1]]);
}
tp--;
}
tp++; stk[tp] = i;
if(tp>1)
{
addh(1,1,n,stk[tp-1]-1,n,f[stk[tp-1]]-f[stk[tp]]);
}
int left = 0,right = tp;
while(left>1;
if(f[i]-f[stk[mid]]>m) {left = mid;}
else {right = mid-1;}
}
int r = stk[left]-1;
int ret = query(1,1,n,r,INF);
ans = max(ans,ret-i+1);
}
printf("%d
",ans);
return 0;
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.