大致上就是一个维护函数的线段树。
大概是标记永久化的妙用!理解还是很好理解的 代码难度也不高。。(这东西不管是谁看都会好吧...
例题:HEOI2013 segment
虽然是强制在线 但是我们的线段树丝毫不需直接插入即可 注意线段树怎么方便怎么写。
题目中没给直接给出斜率我们也尽量带入点的坐标去算 小心掉精度。
这道题是单点询问所以我们标记永久化不需要存整个区间的最大值及最小编号。当然要是区间询问也是可以写的。
值得一提的是我们比两条直线的大小时不要直接比较两端点的坐标大小防止大小一样 但标号不同这种情况 所以可以先判断中点谁最高再比大小要好。
还是放一波代码吧:
```
const int MAXN=40010;
int n,maxx=39989,ans,cnt;
struct wy
{
int l,r,id;
db yl,yr;
inline db k(){return (yr-yl)/(r-l);}
inline db f(int x){return l==r?yl:yl+k()*(x-l);}
inline void limL(int x){yl=f(x);l=x;}
inline void limR(int x){yr=f(x);r=x;}
}t[MAXN<<2],seg;
int vis[MAXN<<2];
inline int pd(wy a,wy b,int x)
{
return fabs(a.f(x)-b.f(x))<=EPS?a.idb.f(x);
}
inline void change(int p,int l,int r,wy ss)
{
if(ss.lr)ss.limR(r);
if(!vis[p]){vis[p]=1;t[p]=ss;return;}
int mid=(l+r)>>1;
if(pd(ss,t[p],mid))swap(ss,t[p]);
if(min(t[p].yl,t[p].yr)>=max(ss.yl,ss.yr))return;
if(t[p].k()>=ss.k())change(zz,l,mid,ss);
else change(yy,mid+1,r,ss);
}
inline void modify(int p,int l,int r,int L,int R)
{
if(L<=l&&R>=r){change(p,l,r,seg);return;}
int mid=(l+r)>>1;
if(L<=mid)modify(zz,l,mid,L,R);
if(R>mid)modify(yy,mid+1,r,L,R);
}
inline wy ask(int p,int l,int r,int x)
{
if(l==r)return t[p];
int mid=(l+r)>>1;wy ss;
if(x<=mid)ss=ask(zz,l,mid,x);
else ss=ask(yy,mid+1,r,x);
if(pd(ss,t[p],x))return ss;
return t[p];
}
int main()
{
freopen("1.in","r",stdin);
n=read();
for(int i=1;i<=n;++i)
{
int op=read();
cnt+=op;
if(!op)
{
int k=(read()+ans-1)%maxx+1;
printf("%d\n",ans=ask(1,1,maxx,k).id);
}
else
{
ll x0,xx,y0,ys;
x0=read();xx=read();
y0=read();ys=read();
x0=(x0+ans-1)%maxx+1;
y0=(y0+ans-1)%maxx+1;
xx=(xx+ans-1)%INF+1;
ys=(ys+ans-1)%INF+1;
if(x0>y0)swap(x0,y0),swap(xx,ys);
if(x0==y0)xx=ys=max(xx,ys);
seg=(wy){x0,y0,cnt,xx,ys};
modify(1,1,maxx,x0,y0);
}
}
return 0;
}
```
好像vis数组没怎么用 因为这道题总坐标都是>0的所以一定都会比初始的要大所以要不要无所谓。
LINK:[SDOI2016游戏](https://www.luogu.com.cn/problem/P4069)
这道题也是比较裸的题目 但是有区间询问我们标记永久化一下区间最小值即可。
LINK:[JSOI2008](https://www.luogu.com.cn/problem/P4254)