Description
sg站在
0
位置,后面有
空间限制 1G , 时间限制 5s
TuCao
这已经是非常好的题意了。。。。原题的信息更加confusing。例如只能朝一个方向传播题解和样例都没解释,声音频率能改也没有特别说明,导致我认为这题无比的复杂。
Preliminary Analysis
由于声音频率是可以改变的。
某个人传话给sg和sg传话他所花的时间可途径都是一样的,把对象反一下就好了。
我们只需要求sg传话给每个人的时间就好。
我们设
Fi
表示sg传话给第i个人所需要的时间。
我们不难想到一个DP式
好的看懂题目这样的DP式就能有50分了= =
然而现场所有人都打了DFS因为以为可以往回走。
Solution
根据这个DP式我们可以知道对于位置
i
我们需要什么:
1.合法的位置
2.合法的
[Xj,Yj]
我们对于
Pi
排个序,那么可选的决策就是一段连续的区间。
那么怎么知道
[Xj,Yj]
合不合法呢?
我们不需要知道。
按照权值建一个线段树,每个决策
[Xj,Yj]
附上该决策值。只需要知道
[Xi,Yi]
内的最小值就可以了。
这样非常暴力,鉴于1G的空间我们不理了。
因为决策区间会移动,所以我们有必要删除队首元素。删除,也就是撤销,是普通线段树无法实现的功能。可持久化?或许可以?应该是不行的空间太大1G都不够用。
没错就是单调队列。
线段树套单调队列。
我们对于线段树的每个区间都开一个单调队列来维护一个该区间内单调递增的决策,一旦遇到位置不合法就弹出队首即可。每次插入都是
logn
的,只会插入
logn
个点。
还有一个问题:
我们查询的区间不一定和之前完全相同,有交集就行。
如果我们只对线段树普通的赋值,完全覆盖才加入,这样就会丢失很多信息,简而言之就是错的。
我们对每个区间维护两个单调队列,Cover和Pass
Cover:完全覆盖该区间的决策的单调队列
Pass:经过该区间的决策的单调队列
也可以理解为
Cover:当前点的信息
Pass:该点及其子树的信息
这样我们查询的时候,除了查询是所有经过的区间的Cover,对于查询区间所完全覆盖的区间,我们把它们的Pass也算上。
这样一来,我们就可以得出正确答案了。
PS.数字范围很大请务必离散化
离散化能不用Hash就别用吧
一个区间在修改时,能更新Cover就没必要更新Pass了,因为Cover
⊆
Pass
常数较大,祝君好运。
此题的思想可以灵活运用于二维矩形赋值,关于维护二维的线段树等等。
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
const int N = 250010;
map<int , int> Hash;
struct Que{
int head,tail;
vector<int> q;
};
struct Node{
int l,r;
Que Cover , Pass;
}tree[N * 20];
struct Data{
int x,y,pos;
}a[N];
int F[N],n,l,mxt,myt,tot,inf,c[N * 2],P,Pos;
void Relable()
{
int td = 0 , id = 0;
for (int i = 1 ; i <= n ; i ++) c[++ td] = a[i].x , c[++ td] = a[i].y;
sort(c + 1 , c + 1 + td);
for (int i = 1 ; i <= td ; i ++) if (!Hash[c[i]]) Hash[c[i]] = ++ id ;
for (int i = 1 ; i <= n ; i ++) a[i].x = Hash[a[i].x] , a[i].y = Hash[a[i].y];
mxt = 1 , myt = id;
}
void Update(Que &t)
{
while (t.tail >= t.head && F[t.q[t.tail]] >= F[P]) t.tail --;
++ t.tail;
if (t.tail < t.q.size()) t.q[t.tail] = P; else t.q.push_back(P);
}
void Mark(int now , int L , int R , int l , int r)
{
if (L == l && r == R)
{
Update(tree[now].Cover);
// Update(tree[now].Pass , p);
return;
}
Update(tree[now].Pass);
int mid = (L + (long long)R) >> 1;
if (r <= mid)
{
if (!tree[now].l)
tree[now].l = ++ tot , tree[tot].Cover.tail = tree[tot].Pass.tail = -1;
Mark(tree[now].l , L , mid , l , r); return ;
}
if (l > mid)
{
if (!tree[now].r)
tree[now].r = ++ tot , tree[tot].Cover.tail = tree[tot].Pass.tail = -1;
Mark(tree[now].r , mid + 1 , R , l , r); return ;
}
if (!tree[now].l)
tree[now].l = ++ tot , tree[tot].Cover.tail = tree[tot].Pass.tail = -1;
if (!tree[now].r)
tree[now].r = ++ tot , tree[tot].Cover.tail = tree[tot].Pass.tail = -1;
Mark(tree[now].l , L , mid , l , mid);
Mark(tree[now].r , mid + 1 , R , mid + 1 , r);
return;
}
inline int Gethead(Que &t)
{
while (t.head <= t.tail && a[t.q[t.head]].pos < Pos) t.head ++;
if (t.head > t.tail) return inf;
return F[t.q[t.head]];
}
int Query(int now , int L , int R , int l , int r)
{
int mid = (L + (long long)R) >> 1 , flag = inf;
/* Gethead(tree[now].Cover);
if (tree[now].Cover.head <= tree[now].Cover.tail)
flag = F[tree[now].Cover.q[tree[now].Cover.head]];*/
flag = Gethead(tree[now].Cover);
if (L == l && R == r)
{
/*Gethead(tree[now].Pass);
if (tree[now].Pass.head <= tree[now].Pass.tail)
flag = min(flag , F[tree[now].Pass.q[tree[now].Pass.head]]);*/
flag = min(flag , Gethead(tree[now].Pass));
return flag;
}
if (r <= mid)
{
if (!tree[now].l) return flag;
return min(flag , Query(tree[now].l , L , mid , l , r));
}
if (l > mid)
{
if (!tree[now].r) return flag;
return min(flag , Query(tree[now].r , mid + 1 , R , l , r));
}
if (tree[now].l) flag = min(flag , Query(tree[now].l , L , mid , l , mid));
if (tree[now].r) flag = min(flag , Query(tree[now].r , mid + 1 , R , mid + 1 , r));
return flag;
}
int main()
{
freopen("2.in" , "r" , stdin);freopen("2.out" , "w" , stdout);
scanf("%d%d" , &n , &l);
mxt = 2000000010;
tot = 1 , inf = N * 2;
for (int i = 2 ; i <= n ; i ++)
{
scanf("%d%d%d" , &a[i].x , &a[i].y , &a[i].pos);
mxt = min(a[i].x , mxt);
myt = max(a[i].y , myt);
}
a[1].x = mxt , a[1].y = myt , a[1].pos = 0;
Relable();
tree[1].Cover.tail = tree[1].Pass.tail = -1;
P = 1 , Pos = 0;
Mark(1 , mxt , myt , a[1].x , a[1].y);
for (int i = 2 ; i <= n ; i ++)
{
Pos = a[i].pos - l;
if (a[i].pos >= l) F[i] = Query(1 , mxt , myt , a[i].x , a[i].y); else F[i] = 0;
//F[i] = Query(1 , mxt , myt , a[i].x , a[i].y);
if (F[i] == inf) {F[i] = -1 ; continue;}
F[i] ++;P = i;
Mark(1 , mxt , myt , a[i].x , a[i].y);
}
for (int i = 2 ; i <= n ; i ++) printf("%d\n" , F[i]);
return 0;
}